2.1 设置调度优先级
进程调度的优先级,这个应该不难理解。简单地说:
l OS在调度进程的时候是遵循一定规则的,优先级高的进程分配CPU的时间多,而优先级低的进程相对分配的CPU时间少。(这个仅是理论上的,具体如何分配是和OS相关的)
下面我们看看AndroidSetThreadPriority的实现。
int androidSetThreadPriority(pid_t tid, int pri) { #if defined(HAVE_PTHREADS) //目前仅支持POSIX //phtread_once保证这个线程创建时会首先执行一次(仅此一次,类似Class的constructor) //checkDoSchedulingGroup函数,该函数判断系统是否设置了”debug.sys.noschedgroups” pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup); if (gDoSchedulingGroup) { if (pri >= ANDROID_PRIORITY_BACKGROUND) { //设置调度策略。这个我们待会会碰到。 rc = set_sched_policy(tid, SP_BACKGROUND); } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) { rc = set_sched_policy(tid, SP_FOREGROUND); } } …… //设置调度优先级。 if (setpriority(PRIO_PROCESS, tid, pri) < 0) { rc = INVALID_OPERATION; } …… }
从上面代码发现,Android直接调用了系统API setpriority,其中有三个参数,其原型是:
int setpriority(int which, int who, int prio);
第一个参数which可选值为PRIO_PROGRESS,表示设置进程;PRIO_PGROUP表示设置进程组;PRIO_USER表示user。 第二个参数who,根据第一个参数的不同,分别指向进程ID;进程组ID和user id。 第三个参数学名叫nice值,从-20到19。是优先级的表示,越大表明越nicer,优先级越低。看来,设置进程调度优先级还是很简单的嘛!
2.2 设置调度策略Linux的进程调度除了简单的设置nice值外,还可以设置调度策略。这个问题我们放到最后讨论。先来看看上层API。
int androidSetThreadSchedulingGroup(pid_t tid, int grp) { …… #if defined(HAVE_PTHREADS) …… if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ? SP_BACKGROUND : SP_FOREGROUND)) { #endif } int set_sched_policy(int tid, SchedPolicy policy) { pthread_once(&the_once, __initialize);//先运行__initialize函数 #if POLICY_DEBUG …… #endif //看看系统是否支持调度策略 if (__sys_supports_schedgroups) { if (add_tid_to_cgroup(tid, policy)) { …… } } else { struct sched_param param; //调度参数,类型为sched_param param.sched_priority = 0; sched_setscheduler(tid,//如果系统不支持的话,直接调用OS的调度策略设置API (policy == SP_BACKGROUND) ? SCHED_BATCH : SCHED_NORMAL, ?m); } }
initialize这个函数很关键,这里的__sys_supports_schedgroups用来检查android系统,而不是OS。
static void __initialize(void) { char* filename; //如果android手机上有/dev/cpuctl/tasks文件,则__sys_supports_schedgroups为1 //目前我的索爱手机并没有该文件。 if (!access("/dev/cpuctl/tasks", F_OK)) { __sys_supports_schedgroups = 1; filename = "/dev/cpuctl/tasks"; normal_cgroup_fd = open(filename, O_WRONLY); …… filename = "/dev/cpuctl/bg_non_interactive/tasks"; bg_cgroup_fd = open(filename, O_WRONLY); …… } else { __sys_supports_schedgroups = 0; } }
目前还没有找到解释/dev/cpuctl/tasks这个特殊文件的地方。有明白的网友请不吝赐教.下面我们看看linux提供的设置调度策略的函数,其原型是:
int sched_setscheduler(pid_t pid, int policy,const struct sched_param *param);
第一个参数为进程id。 第二个参数为调度策略,目前android支持SCHED_OTHER,标准round-robin分时共享策略(也就是默认的策略);SCHED_BATCH,针对具有batch风格(批处理)进程的调度策略;SCHED_IDLE,针对优先级非常低的适合在后台运行的进程。另外,linux还支持实时(Real-time)调度策略(SCHED_FIFO,先入先出调度策略,SCHED_RR,round-robin调度策略,也就是循环调度。)。 param参数中最重要的是该结构体中的sched_priority变量。针对上面三种非实时调度策略,该值必须为零。 2.3 小结从前面可以看出,Android上进程调度还是依赖OS提供的调度机制。当然上层API还是比较简单易懂的,但是Linux OS调度到底是怎么样的呢?不妨探讨一下。