Linux线程的优先级调度问题

forthcoming 2010-05-11 02:10:53
Linux内核的三种调度策略:

  1,SCHED_OTHER 分时调度策略,

  2,SCHED_FIFO实时调度策略,先到先服务。一旦占用cpu则一直运行。一直运行直到有更高优先级任务到达或自己放弃

  3,SCHED_RR实时调度策略,时间片轮转。当进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平

下面的一段程序的运行结果与预想中的不太一样,请高手指教一下:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>


void FunThread1()
{
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");

sched_yield();

for(i=1;i<10;i++)
{
for(j=1;j<50000000;j++)
{
}
printf("thread 1\n");
}
printf("Thread1 exit\n");
}
void FunThread2()
{
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");

sched_yield();

for(i=1;i<10;i++)
{
for(j=1;j<50000000;j++)
{
}
printf("thread 2\n");
}
printf("Thread2 exit\n");
}
void FunThread3()
{
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");

sched_yield();

for(i=1;i<10;i++)
{
for(j=1;j<50000000;j++)
{
}
printf("thread 3\n");
}

printf("Thread3 exit\n");
}
int main()
{
int i;
i=getuid();
if(i==0)
printf("The current user is root\n");
else
printf("The current user is not root\n");

pthread_t ppid1,ppid2,ppid3;
struct sched_param param;
param.sched_priority=51;
pthread_attr_t attr,attr2,attr1;
pthread_attr_init(&attr);
pthread_attr_init(&attr2);
pthread_attr_init(&attr1);
pthread_attr_setschedpolicy(&attr2,SCHED_RR);
pthread_attr_setschedparam(&attr2,¶m);
//do not inherit father's attr
pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);

param.sched_priority=21;
pthread_attr_setschedpolicy(&attr1,SCHED_RR);
pthread_attr_setschedparam(&attr1,¶m);
pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);


pthread_create(&ppid3,&attr,FunThread3,NULL);
pthread_create(&ppid2,&attr1,FunThread2,NULL);
pthread_create(&ppid1,&attr2,FunThread1,NULL);
pthread_join(ppid3,NULL);
pthread_join(ppid2,NULL);
pthread_join(ppid1,NULL);
pthread_attr_destroy(&attr);
pthread_attr_destroy(&attr2);
return 0;
}

实际运行结果:
The current user is root
SCHED_RR
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
Thread2 exit
SCHED_RR
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
Thread1 exit
SCHED_OTHER
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
Thread3 exit

我的预想结果:(理由:thread1的优先级(51)比thread2的优先级别(21)高,应该优先运行)
The current user is root
SCHED_RR
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
Thread1 exit
SCHED_RR
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
Thread2 exit
SCHED_OTHER
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
Thread3 exit
...全文
1617 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
forthcoming 2010-05-13
  • 打赏
  • 举报
回复
sorry,上面的结果贴错了,重新贴一遍:
The current user is root
SCHED_OTHER
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
SCHED_RR
SCHED_RR
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
Thread1 exit
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
Thread2 exit
thread 3
Thread3 exit
forthcoming 2010-05-13
  • 打赏
  • 举报
回复
非常感谢sabflying的回答。

我按照你修改的方法,进行了一下尝试,没有出现你的结果,可能linux的版本不一样。

不过按照你的思路,进行了如下的修改,能够验证linux的线程抢占结果。
void FunThread1()
{
sleep(1); //thread1休眠1秒
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");

//sched_yield();

for(i=1;i<10;i++)
{
for(j=1;j<50000000;j++)
{
}
printf("thread 1\n");
//sleep(1);
}
printf("Thread1 exit\n");
}
void FunThread2()
{
sleep(1); //thread2也休眠1秒

int i,j,m;

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");

//sched_yield();

m = 0;
for(i=1;i<10;i++)
{
for(j=1;j<50000000;j++)
{
m++; //增加thread2内部处理时间
}
printf("thread 2\n");
}
printf("Thread2 exit\n");
}
void FunThread3()
{
//sleep(1); //thread3不进行休眠,直接进行运行
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");

//sched_yield();

for(i=1;i<10;i++)
{
for(j=1;j<50000000;j++)
{
}
printf("thread 3\n");
}

printf("Thread3 exit\n");
}

以上运行的结果:
The current user is root
SCHED_OTHER
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
Thread3 exit
SCHED_RR
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
Thread1 exit
SCHED_RR
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
Thread2 exit


可以清晰的看到thread3被抢占,thread2也被优先级别1直接抢占了。
forthcoming 2010-05-13
  • 打赏
  • 举报
回复
非常感谢sabflying的回答。

我按照你修改的方法,进行了一下尝试,没有出现你的结果,可能linux的版本不一样。

不过按照你的思路,进行了如下的修改,能够验证linux的线程抢占结果。
void FunThread1()
{
sleep(1); //thread1休眠1秒
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");

//sched_yield();

for(i=1;i<10;i++)
{
for(j=1;j<50000000;j++)
{
}
printf("thread 1\n");
//sleep(1);
}
printf("Thread1 exit\n");
}
void FunThread2()
{
sleep(1); //thread2也休眠1秒

int i,j,m;

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");

//sched_yield();

m = 0;
for(i=1;i<10;i++)
{
for(j=1;j<50000000;j++)
{
m++; //增加thread2内部处理时间
}
printf("thread 2\n");
}
printf("Thread2 exit\n");
}
void FunThread3()
{
//sleep(1); //thread3不进行休眠,直接进行运行
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");

//sched_yield();

for(i=1;i<10;i++)
{
for(j=1;j<50000000;j++)
{
}
printf("thread 3\n");
}

printf("Thread3 exit\n");
}

以上运行的结果:
The current user is root
SCHED_OTHER
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
Thread3 exit
SCHED_RR
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
Thread1 exit
SCHED_RR
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
Thread2 exit

可以清晰的看到thread3被抢占,thread2也被优先级别1直接抢占了。
sabflying 2010-05-12
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 forthcoming 的回复:]
引用 2 楼 sabflying 的回复:
2、linux上优先级的数值越小,优先级越高
LZ代码中的确是thread1优先级最高


我用的是虚拟机CentOS,linux版本:2.6.18

SCHED_FIFO和SCHED_RR两种调度策略中,数值越大,优先级别越高。

void FunThread1()
void FunThread2()
void FunThread……
[/Quote]

2.6.18内核的调度是以线程为单位的进行进程调度的
forthcoming 2010-05-12
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 sabflying 的回复:]
2、linux上优先级的数值越小,优先级越高
LZ代码中的确是thread1优先级最高
[/Quote]

我用的是虚拟机CentOS,linux版本:2.6.18

SCHED_FIFO和SCHED_RR两种调度策略中,数值越大,优先级别越高。

void FunThread1()
void FunThread2()
void FunThread3()
这3个线程都在一个进程中,应该用的是进程的一个队列吧?

而且每个线程函数启动的时候都调用了sched_yield(),释放调度权利。

FunThread3是最先调度的函数,但是由于它的优先级是SCHED_OTHER,
所以被优先级别是SCHED_RR的FunThread2所强占,这个很合理。

我的问题是:FunThread1的优先级别明明比FunThread2高,为什么不能抢占。
sabflying 2010-05-12
  • 打赏
  • 举报
回复
修改后的代码,可以满足LZ的要求。
此外,struct sched_param param; 参数中sched_priority的确是这个值愈大,优先级越高。

系统对传递的参数进行了处理


#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>


void FunThread1()
{
sleep(3);
/*Thread 1休眠3秒,Thread3和thread2休眠2秒,这样可以保证三个进程都能顺利创建,
由于优先级低的实时线程thread2比优先级高的thread1优先运行,只要保证thread2的循环
执行时间超过1秒,就可以出现线程抢占的情况.
*/
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");

sched_yield(); //就本进程而言这一句可有可无,不影响结果,原因上面的帖子已经说过了,这里不在重复

for(i=1;i<10;i++)
{
for(j=1;j<50000000;j++)
{
}
printf("thread 1\n");
}
printf("Thread1 exit\n");
}
void FunThread2()
{
sleep(2); //休眠便于thread1能够正常创建,否则直到该线程退出才会执行thread1创建的代码
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");

sched_yield();//就本进程而言这一句可有可无,不影响结果,原因上面的帖子已经说过了,这里不在重复
//增大循环的次数以便增加该线程执行的时间,保证thread1被调度时thread2仍在运行
for(i=1;i<100;i++)
{
for(j=1;j<50000000;j++)
{
}
printf("thread 2\n");
}
printf("Thread2 exit\n");
}
void FunThread3()
{
sleep(3);
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");

sched_yield();

for(i=1;i<10;i++)
{
for(j=1;j<50000000;j++)
{
}
printf("thread 3\n");
}

printf("Thread3 exit\n");
}
int main()
{
int i;
i=getuid();
if(i==0)
printf("The current user is root\n");
else
printf("The current user is not root\n");

pthread_t ppid1,ppid2,ppid3;
struct sched_param param;
param.sched_priority=51;
pthread_attr_t attr,attr2,attr1;
pthread_attr_init(&attr);
pthread_attr_init(&attr2);
pthread_attr_init(&attr1);
pthread_attr_setschedpolicy(&attr2,SCHED_RR);
pthread_attr_setschedparam(&attr2,¶m);
//do not inherit father's attr
pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);

param.sched_priority=21;
pthread_attr_setschedpolicy(&attr1,SCHED_RR);
pthread_attr_setschedparam(&attr1,¶m);
pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);

pthread_create(&ppid3,&attr,FunThread3,NULL);
pthread_create(&ppid2,&attr1,FunThread2,NULL);
pthread_create(&ppid1,&attr2,FunThread1,NULL);
pthread_join(ppid3,NULL);
pthread_join(ppid2,NULL);
pthread_join(ppid1,NULL);
pthread_attr_destroy(&attr);
pthread_attr_destroy(&attr2);
return 0;


}


gcc -o test1 -lpthread priotest.c
./test1 >a.log

cat ./a.log
内容节选如下

The current user is root
SCHED_RR
thread 2
thread 2
thread 2
thread 2
thread 2
SCHED_RR
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
thread 1
Thread1 exit
thread 2
thread 2
thread 2
thread 2
thread 2
..........
thread 2
Thread2 exit
SCHED_OTHER
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
Thread3 exit

当然也可以通过修改thread3的休眠时间及循环次数,来验证实时进程对一般进程的抢占,
sabflying 2010-05-12
  • 打赏
  • 举报
回复
再补充一下LZ的假设是理想情况下的结果,它必须满足以下条件:

1、在调度时,三个进程同时存在于一个运行对列中

2、在各个线程运行期间不会出现线程的抢占以及线程优先级变化
即下列函数均能在分配的时间片内完成运行(请注意线程用完时间片后,会出现变化)
void FunThread1()
void FunThread2()
void FunThread3()


而这个进程在实际运行中可能出现多种意外(单cpu 情况下)
1、先产生的thread3执行完成并退出了thread2还没有产生,这与cpu 的运算速度以及
FunThread3()的执行速度、主线程的优先级相关,存在一定的偶然性。

2、如果thread3需要在cpu 上长时间运行,还存在被thread2抢占的情况,
这样会出现thread3的输出中会出现thread2的输出。
加大FunThread3()的循环次数可能出现这种情况,在LZ的代码中出现的可能性很低

3、thread2执行完成了thread1还没有产生,LZ的代码出现这种情况是必然出现的,
因为thread2的全局优先级高于主线程,cpu 执行thread2,直到thread2退出
才会执行主线程的
pthread_create(&ppid1,&attr2,FunThread1,NULL);




需要说明的是即使按照我上面给出的建议执行也不一定会出现LZ期望的情况,
只是在单CPU的情况下加大了出现的概率。而在SMP处理器上运行结果更不确定。


sabflying 2010-05-12
  • 打赏
  • 举报
回复
[Quote=引用楼主 forthcoming 的回复:]
Linux内核的三种调度策略:

  1,SCHED_OTHER 分时调度策略,

  2,SCHED_FIFO实时调度策略,先到先服务。一旦占用cpu则一直运行。一直运行直到有更高优先级任务到达或自己放弃

  3,SCHED_RR实时调度策略,时间片轮转。当进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平

下面的……
[/Quote]


1、如果是在SMP系统上结果是不确定的,请指明运行的硬件/软件环境,
两个实时调度的线程如果不在同一个调度队列上,线程优先级高并不一定会先运行。

2、linux上优先级的数值越小,优先级越高
LZ代码中的确是thread1优先级最高

3、上述程序存在其他线程还未产生,前一个线程已经执行完毕的情况


void FunThread1()
void FunThread2()
void FunThread3()

应该先sleep(1);
一段时间,尽可能的保证调度时三个线程都在运行队列中,
当然如果
pthread_create(&ppid3,&attr,FunThread3,NULL);
pthread_create(&ppid2,&attr1,FunThread2,NULL);
pthread_create(&ppid1,&attr2,FunThread1,NULL);
任一个执行时间超过10ms或前两个执行时间超过10ms都会导致运行结果出现偏差,因为
cpu 的调度周期为10ms


sabflying 2010-05-12
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 forthcoming 的回复:]
引用 2 楼 sabflying 的回复:
2、linux上优先级的数值越小,优先级越高
LZ代码中的确是thread1优先级最高


我用的是虚拟机CentOS,linux版本:2.6.18

SCHED_FIFO和SCHED_RR两种调度策略中,数值越大,优先级别越高。

void FunThread1()
void FunThread2()
void FunThread……
[/Quote]

1、sched_yield()函数对于实时进程和普通进程的意义是不一样的,
对于实时进程调用sched_yield()后,改线程依然处于active运行队列中,仍然是就绪状态
如果没有优先级比它高的线程存在,调度后依然运行该线程
因此即使Thread2中执行了sched_yield()函数,在下次调用时还是不会执行主线程(main函数)
,主线程执行不了
pthread_create(&ppid1,&attr2,FunThread1,NULL);
thread1在Thread2执行完以前根本不会执行。
LZ所期待的进程抢占也就不可能发生。

而普通线程执行sched_yield()函数后,状态仍为就绪状态但会移动到expired的运行队列,
active运行队列执行不完,该线程不会运行在cpu 上。

关于这一点LZ可以参考内核代码:sched.c中的long sys_sched_yield(void)

2、对于Linux的优先级数值愈大,优先级越低是可以确定的。
这和调度方式没有关系,实时进程的优先级范围是1~99,1为最高

上次的回复应该是thread2的优先级高于thread1,以下是param中的sched_priority的说明请参考
sched_priority
When you get the scheduling parameters, this member reflects the priority that was assigned to the thread or process. It doesn't reflect any temporary adjustments due to priority inheritance.

When you set the scheduling parameters, set this member to the priority that you want to use. The priority must be between the minimum and maximum values returned by sched_get_priority_min() and sched_get_priority_max() for the scheduling policy.



3,286

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 实用资料发布区
社区管理员
  • 实用资料发布区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧