关于linux调度策略的学习总结
——————————————————————————————————
这里只做出出一些遇到问题的总结,对应线程的基础熟悉设置等参考sun公司 的《多线程编程指南》非常详细讲述了posix线程库。
By Water- Aug,17th.2010
——————————————————————————————————
线程的调度策略分为3个:SCHED_OTHER,SCHED_FIFO,SCHED_RR。
SCHED_OTHER是非实时分时调度策略,线程优先级为0;
试验结果(linux2.6 Montavista 5.0):每个线程都不能强占其它线程,但是线程都受到时间片的限制,并不是线程不主动退出(包括被阻塞),就会一直占用。
但是在sun公司的 《多线程编程手册》中,其说这种情况 线程会一直占用。
SCHED_FIFO是实时先进先出调度策略,即一当占用CPU,除非自己阻塞或结束或有更高优先级线程,否则会一直运行,线程优先级为1-99;
线程会按不同的优先级来分为不同的队列,同优先级的线程是按FIFO来调度的。
SCHED_RR是实时分时调度策略,其不会一直占用CPU,运行一个时间片后会让出CPU给自己同优先级的线程;其实SCHED_RR与SCHED_FIFO基本是相似的,只是前者会受到时间片的限制,相同优先级的线程,用时间片来调度。而FIFO的话,正在运行的线程,是不会被其他同优先级线程强占的,除非自己主动退出或被阻塞。所以在采用FIFO策略时,千万别使用一直占用的线程(不主动退出,也没有挂起的条件),否则其他同优先级线程永远不会运行了。这种情况最好使用RR策略。
指出:SCHED_OTHER是不支持优先级使用的,而SCHED_FIFO和SCHED_RR支持优先级的使用,他们分别为1和99,数值越大优先级越高。实时调度策略会抢占非实时调度策略,即只要有SCHED_FIFO或SCHED_RR这两个实时调度策略的线程,像SCHED_OTHER的非实时调度策略的线程就不会得到运行,除非所有的实时调度策略的线程阻塞或结束。
下面测试程序thread_attr_test.c来测试线程的缺省属性;
//thread_attr_test.c
#include
#include
#include
#include
#include
void * thrd_fun( void * arg)
{
int my_policy;
struct sched_param my_param;
int status;
pid_t pid;
pid = getpid();
printf("my pid is %d \n",pid);
status = pthread_getschedparam ( pthread_self (), &my_policy, &my_param );
printf ("thread_routine running policy is %s,priority is %d \n", (my_policy == SCHED_FIFO ?"FIFO"
: (my_policy == SCHED_RR ?"RR"
: (my_policy == SCHED_OTHER ? "OTHER"
: " UNKOWN" ))),
my_param.sched_priority);
}
int main (int argc, char *argv[])
{
pthread_t thread_id;
pthread_attr_t thread_attr;
int thread_policy;
struct sched_param thread_param;
int status ,rr_min_priority ,rr_max_priority;
int inherit;
int detachstate;
int policy;
int scope;
struct sched_param param;
pid_t pid;
pid = getpid();
printf("main pid is %d\n",pid);
status = pthread_attr_init ( &thread_attr);
status = pthread_attr_getschedpolicy ( &thread_attr , &thread_policy);
status = pthread_attr_getschedparam ( &thread_attr, &thread_param);
printf ("default policy is %s,priority is %d \n", (thread_policy == SCHED_FIFO ?"FIFO"
: (thread_policy == SCHED_RR ?"RR"
: (thread_policy == SCHED_OTHER ? "OTHER"
: " UNKOWN" ))),
thread_param.sched_priority);
pthread_attr_getinheritsched(&thread_attr,&inherit);
if(inherit==PTHREAD_EXPLICIT_SCHED)
printf("PTHREAD_EXPLICIT_SCHED\n");
if(inherit==PTHREAD_INHERIT_SCHED)
printf("PTHREAD_INHERIT_SCHED\n");
pthread_attr_getdetachstate(&thread_attr,&detachstate);
if(detachstate==PTHREAD_CREATE_DETACHED)
printf("PTHREAD_CREATE_DETACHED\n");
if(detachstate==PTHREAD_CREATE_JOINABLE)
printf("PTHREAD_CREATE_JOINABLE\n");//非分离
pthread_attr_getschedpolicy(&thread_attr,&policy);
if(policy==SCHED_OTHER)
printf("SCHED_OTHER\n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
if(policy==SCHED_RR)
printf("SCHED_RR\n");
pthread_attr_getscope(&thread_attr,&scope);
if(scope==PTHREAD_SCOPE_SYSTEM)
printf("PTHREAD_SCOPE_SYSTEM\n");
if(scope==PTHREAD_SCOPE_PROCESS)
printf("PTHREAD_SCOPE_PROCESS\n");
pthread_attr_getschedparam(&thread_attr,¶m);
printf("priority:%d\n",param.sched_priority);
#if defined (_POSIX_THREAD_PRIORIY_SCHEDULING )
printf("supports");
#else
printf("not supports\n");
#endif
//struct sched_param param;
param.sched_priority=1;
pthread_attr_setschedpolicy(&thread_attr,SCHED_FIFO);
pthread_attr_setschedparam(&thread_attr,¶m);//设置成实时策略后必须设定优先级,否则线程将创建失败
pthread_attr_setinheritsched(&thread_attr,PTHREAD_EXPLICIT_SCHED); //必须把继承属性修改为PTHREAD_EXPLICIT_SCHED才能有效
//否则将继续继承父进程的策略
status = pthread_create( &thread_id ,&thread_attr, thrd_fun , NULL);
if (status != 0)
{
printf("can't creat!\n");
exit (1);
}
status = pthread_join (thread_id ,NULL);
return 0;
}
运行的结果为(FC12-2.6.31.5内核):
main pid is 4318
default policy is OTHER,priority is 0
PTHREAD_INHERIT_SCHED
PTHREAD_CREATE_JOINABLE
SCHED_OTHER
PTHREAD_SCOPE_SYSTEM
priority:0
not supports
my pid is 4318
thread_routine running policy is FIFO,priority is 1
运行的结果为(在arm开发板上2.4.18的内核):
main pid is 111
default policy is OTHER,priority is 0
PTHREAD_EXPLICIT_SCHED 这里和2.6的内核属性不同??
PTHREAD_CREATE_JOINABLE
SCHED_OTHER
PTHREAD_SCOPE_SYSTEM
priority:0
not supports
my pid is 113
thread_routine running policy is FIFO,priority is 1
从结果我们可以得出其缺省属性为:
OTHER非实时调度策略,且优先级为0(无优先级高低之分);
为继承属性(2.6) 非继承(2.4);
为非分离属性;
为绑定属性,即与系统中所有线程(包括其他进程的线程)竞争。
经过pthread_attr_setschedpolicy 设置后把子线程的调度策略设置成了FIFO,且优先级为1;所设定的优先级范围必须在最大和最小值之间。可以通过sched_get_priority_max和sched_get_priority_min来获取。这程序中只是简单的测试。
需要注意的是:
如果修改了调度策略为实时的(即FIFO或RR),则必须为其设置优先级,否则线程将创建失败;记住要把继承属性修改为PTHREAD_EXPLICIT_SHED,否则子线程将继续继承父线程的相关策略,使得策略设置无效。
存在的问题:
有些系统需要定义_POSIX_THREAD_PRIORITY_SCHEDULING 才能设置线程的调度策略。但本次试验中测试出系统没有定义有些系统需要定义_POSIX_THREAD_PRIORITY_SCHEDULING 但仍然可以设置线程的调度策略,有点不明白。
调度策略的验证:
下面对SCHED_FIFO是实时先进先出调度策略,即一当占用CPU,除非自己阻塞或结束或有更高优先级线程,否则会一直运行;这个策略进行验证。
测试程序thread_shed_test.c如下:
#include
#include
#define FIFO_TEST
void *FunThread1(void *arg)
{
int i,j;
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(),&policy,¶m);
if(policy==SCHED_OTHER)
printf("SCHED_OTHER\n");
if(policy==SCHED_RR)
printf("SCHED_RR\n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
for(i=1;i <500;i++)
{
for(j=1;j <50000;j++)
{
}
//while(1); //调用这个来测试 FIFO时候受时间片的限制
printf("thread 1\n");
}
printf("Thread1 exit\n");
}
void* FunThread2(void *arg)
{
int i;
// for(i=1;i <5000;i++)
sched_yield();
sched_yield();
printf("Thread2 exit\n");
}
void* FunThread3(void *arg)
{
int i;
// for(i=1;i <5000;i++)
sched_yield();
sched_yield();
printf("Thread3 exit\n");
}
int main()
{
int i;
pthread_t ppid1,ppid2,ppid3;
struct sched_param param;
pthread_attr_t attr,attr2;
i=getuid();
if(i==0)
printf("The current user is root\n");
else
printf("The current user is not root\n");
param.sched_priority=1;
pthread_attr_init(&attr);
pthread_attr_init(&attr2);
pthread_attr_setschedpolicy(&attr2,SCHED_FIFO);
pthread_attr_setschedparam(&attr2,¶m);
pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED); //新加,指定不继承父线程调度策略
#ifdef FIFO_TEST
pthread_create(&ppid1,&attr2,FunThread1,NULL);
#else
pthread_create(&ppid1,NULL,FunThread1,NULL);
#endif
pthread_create(&ppid2,&attr,FunThread2,NULL);
pthread_create(&ppid3,&attr,FunThread3,NULL);
pthread_join(ppid1,NULL);
pthread_join(ppid2,NULL);
pthread_join(ppid3,NULL);
pthread_attr_destroy(&attr);
pthread_attr_destroy(&attr2);
return 0;
}
运行的结果为(FC12-2.6.31.5内核):
SCHED_FIFO
thread 1
thread 1
thread 1
.
.
.
.
Thread 1
thread 1
thread 1
Thread1 exit
Thread2 exit
Thread3 exit
在main函数里创建线程一时将其调度策略设置为SCHED_FIFO,优先级为1,线程二和线程三的调度策略为SCHED_OTHER,优先级为0,正确结果应该是线程一先运行结束才会轮到线程二和线程三。从运行结果来看似乎正确,但请看后文;
若改为用OTHER方式(注释掉‘#define FIFO_TEST’ )则结果为:
SCHED_OTHER
thread 1
thread 1
thread 1
.
.
.
.
Thread 1
Thread2 exit
thread 1
thread 1
.
.
.
.
thread 1
thread 1
Thread3 exit
thread 1
thread 1
.
.
.
.
thread 1
thread 1
Thread1 exit
这种情况下,是时分调度的,3个线程都有时间片限制,时间片到则被其它线程代替。结果验证时正确的。
但是是否线程1(FIFO策略)的只要自己不退让或阻塞就不会被线程2或3 强占了??
在FunThread1()中加入while(1)死循环后再来测试
运行结果为:(FC12-2.6.31.5内核):
The current user is root
SCHED_FIFO
Thread2 exit
Thread3 exit
--
发现FIFO的线程1,在运行一段时间后线程2和3还是得以执行了。这证明在该系统上即使是FIFO的线程,其也受到了一个时间片的限制,在系统规定的时间片到时,其必须让出给其它线程执行。否则pc上的FC12这个系统将不能做其它的事情了(显然不可以)。但是这时候也可以明显的发现,此时PC机上的FC12系统对其它的操作响应(如鼠标等)已经很慢了。这证明这个所谓的时间片应该比较长。
但是把这个程序在arm开发板上运行:
运行的结果为(在arm开发板上2.4.18的内核):
The current user is root
SCHED_FIFO
------
结果显示与FIFO的理论完全相符合,即即一当占用CPU,除非自己阻塞或结束或有更高优先级线程,否则会一直运行。
两种平台上的不同的原因猜想:
可能在PC机上的FC12加入了时间片的限制,来时这个系统不容易崩溃。而ARM开发板上的linux则没有做相关处理。