在linux中,为什么正常进程仍然可以运行而实时进程不退出?
In linux, why a normal process can still run while real time process doesn't exit?
我写了一个 c 程序来测试 linux 调度器。这是我的代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void Thread1()
{
sleep(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 1 \n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
/* for(i=1;i<100;i++) */
while(1)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 1\n");
}
printf("Pthread 1 exit\n");
}
void Thread2()
{
sleep(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");
/* for(i=1;i<10;i++) */
while(1)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 2\n");
}
printf("Pthread 2 exit\n");
}
void Thread3()
{
sleep(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");
/* for(i=1;i<10;i++) */
while(1)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 3\n");
}
printf("Pthread 3 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;
pthread_attr_t attr3,attr1,attr2;
pthread_attr_init(&attr1);
pthread_attr_init(&attr3);
pthread_attr_init(&attr2);
param.sched_priority = 97;
pthread_attr_setschedpolicy(&attr1,SCHED_RR);
pthread_attr_setschedparam(&attr1,¶m);
pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);
param.sched_priority = 98;
pthread_attr_setschedpolicy(&attr2,SCHED_RR);
pthread_attr_setschedparam(&attr2,¶m);
pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);
pthread_create(&ppid3,&attr3,(void *)Thread3,NULL);
pthread_create(&ppid2,&attr2,(void *)Thread2,NULL);
pthread_create(&ppid1,&attr1,(void *)Thread1,NULL);
pthread_join(ppid3,NULL);
pthread_join(ppid2,NULL);
pthread_join(ppid1,NULL);
pthread_attr_destroy(&attr2);
pthread_attr_destroy(&attr1);
return 0;
}
在这个程序中,我创建了一个具有默认属性的线程和两个调度策略为SCHED_RR和特定优先级的线程。我的问题是:
当我 运行 程序时,我几乎看不到线程 1 的输出。这是怎么发生的? 我认为线程 1 和线程 2 是实时进程,线程 3 是普通进程。 所以线程 3 永远不会 运行 直到线程 1 和线程 2 退出。但是在我的程序中线程1和线程2永远不会退出,所以我预计实际上只有线程2可以运行。 为什么我能看到线程2和线程3的输出,而看不到线程1的输出?
以下建议代码:
- 它只检查系统函数的一些错误状态值
- 显示 OP 出现问题的原因
- 遵循公理:每行只有一个语句,每个语句(最多)一个变量声明。
- 更正了编译器在 OP 代码中指出的许多问题
注意:这是 运行 ubuntu linux 16.04
#include <stdio.h>
//#include <unistd.h> -- contents not used
#include <stdlib.h>
#include <pthread.h>
void *Thread1( void *data );
void *Thread2( void *data );
void *Thread3( void *data );
void *Thread1( void *data )
{
(void)data;
sleep(1);
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 1 \n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
for( size_t i=0; i<1000; i++ )
{
printf("thread 1\n");
}
printf("Pthread 1 exit\n");
pthread_exit( NULL );
}
void *Thread2( void *data )
{
(void)data;
sleep(1);
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( size_t i = 0; i< 1000; i++ )
{
printf("thread 2\n");
}
printf("Pthread 2 exit\n");
pthread_exit( NULL );
}
void *Thread3( void *data )
{
(void)data;
sleep(1);
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( size_t i = 0; i<1000; i++ )
{
printf("thread 3\n");
}
printf("Pthread 3 exit\n");
pthread_exit( NULL );
}
int main( void )
{
unsigned 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;
pthread_t ppid2;
pthread_t ppid3;
struct sched_param param;
pthread_attr_t attr3;
pthread_attr_t attr1;
pthread_attr_t attr2;
pthread_attr_init(&attr1);
pthread_attr_init(&attr3);
pthread_attr_init(&attr2);
param.sched_priority = 97;
pthread_attr_setschedpolicy(&attr1,SCHED_RR);
pthread_attr_setschedparam(&attr1,¶m);
pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);
param.sched_priority = 98;
pthread_attr_setschedpolicy(&attr2,SCHED_RR);
pthread_attr_setschedparam(&attr2,¶m);
pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);
int create3 = pthread_create( &ppid3, &attr3, Thread3, NULL );
if( create3 )
{
fprintf( stderr, "pthread_create for thread 3 failed with status: %d\n", create3 );
//exit( EXIT_FAILURE );
}
int create2 = pthread_create( &ppid2, &attr2, Thread2, NULL );
if( create2 )
{
fprintf( stderr, "pthread_create for thread 2 failed with status: %d\n", create2 );
//exit( EXIT_FAILURE );
}
int create1 = pthread_create( &ppid1, &attr1, Thread1, NULL );
if( create1 )
{
fprintf( stderr, "pthread_create for thread 1 failed with status: %d\n", create1 );
//exit( EXIT_FAILURE );
}
pthread_join(ppid3,NULL);
pthread_join(ppid2,NULL);
pthread_join(ppid1,NULL);
pthread_attr_destroy(&attr3);
pthread_attr_destroy(&attr2);
pthread_attr_destroy(&attr1);
return 0;
}
运行以普通用户身份运行程序会导致:
The current user is not root
pthread_create for thread 2 failed with status: 1
pthread_create for thread 1 failed with status: 1
SCHED_OTHER
thread 3 <-- repeats 1000 times
Pthread 3 exit
运行以 root 身份运行程序会导致:
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
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
SCHED_OTHER
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 2
SCHED_RR 1
thread 1
thread 1
thread 2
thread 3
thread 3
thread 3
thread 2
thread 1
thread 1
thread 1
thread 1
thread 1
... continues for a total of 3000 lines and
... as each thread completes it outputs:
pthread 1 exit -OR- pthread 2 exit -OR- pthread 3 exit
回答 OP 问题:
每次实时线程调用 printf()
时,其他线程都有机会 运行。部分原因是执行了上下文切换,包括在用户和 OS 进程之间切换的上下文切换。
线程 3 可以是 运行 因为 0.05s 是为非 运行 时间任务保留的,通过 echo -1 > /proc/sys/kernel/sched_rt_runtime_us
:
禁用它
The default values for sched_rt_period_us
(1000000 or 1s) and
sched_rt_runtime_us
(950000 or 0.95s). This gives 0.05s to be used by
SCHED_OTHER
(non-RT tasks). These defaults were chosen so that a run-away
realtime tasks will not lock up the machine but leave a little time to recover it. By setting runtime to -1 you'd get the old behaviour back.
线程1不能是运行因为线程2有更高的优先级(注意99是pthread调用中最高的RT优先级,这与内部Linux编号相矛盾并解释here), round-robin调度只在具有相同优先级的进程队列中执行:
SCHED_RR
tasks are scheduled by priority, and within a certain priority they are scheduled in a round-robin fashion. Each SCHED_RR
task within a certain priority runs for its allotted timeslice, and then returns to the bottom of the list in its priority array queue.
Understanding the Linux 2.6.8.1 CPU Scheduler
关于如何找出发生这种情况的原因的一些说明。为此,我们需要源代码和动态跟踪器,例如 SystemTap。通过 scheduler.ctxswitch
探测器切换线程(或更准确地说 上下文切换 )can be traced,它是 sched_switch
跟踪点的包装器。
检查跟踪点周围的源代码表明新任务由调用 pick_next_task
:
的 __schedule
函数处理
3392 next = pick_next_task(rq, prev, cookie);
...
3397 if (likely(prev != next)) {
...
3402 trace_sched_switch(preempt, prev, next);
爬取源代码将我们引向 pick_next_task_rt
,在某些情况下 returns NULL 而不是我们的线程。 SystemTap 时间到了!
# stap -e 'probe kernel.function("pick_next_task_rt").return {
if ($return == 0) {
println($rq->rt$) } }' -c ./a.out
...
{.active={...}, .rt_nr_running=2, .highest_prio={...}, .rt_nr_migratory=2, .rt_nr_total=2,
.overloaded=1, .pushable_tasks={...}, .rt_throttled=1, .rt_time=950005330, .rt_runtime=950000000,
.rt_runtime_lock={...}, .rt_nr_boosted=0, .rq=0xffff8801bfc16c40,
.leaf_rt_rq_list={...}, .tg=0xffffffff81e3d480}
SCHED_OTHER
因此,似乎 rt_time
大于 950 毫秒,并且当我们切换到 SCHED_OTHER
时设置了 rt_throttled
标志。进一步谷歌搜索导致 this answer 和上面链接的文档。
我写了一个 c 程序来测试 linux 调度器。这是我的代码:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void Thread1()
{
sleep(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 1 \n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
/* for(i=1;i<100;i++) */
while(1)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 1\n");
}
printf("Pthread 1 exit\n");
}
void Thread2()
{
sleep(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");
/* for(i=1;i<10;i++) */
while(1)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 2\n");
}
printf("Pthread 2 exit\n");
}
void Thread3()
{
sleep(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");
/* for(i=1;i<10;i++) */
while(1)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 3\n");
}
printf("Pthread 3 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;
pthread_attr_t attr3,attr1,attr2;
pthread_attr_init(&attr1);
pthread_attr_init(&attr3);
pthread_attr_init(&attr2);
param.sched_priority = 97;
pthread_attr_setschedpolicy(&attr1,SCHED_RR);
pthread_attr_setschedparam(&attr1,¶m);
pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);
param.sched_priority = 98;
pthread_attr_setschedpolicy(&attr2,SCHED_RR);
pthread_attr_setschedparam(&attr2,¶m);
pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);
pthread_create(&ppid3,&attr3,(void *)Thread3,NULL);
pthread_create(&ppid2,&attr2,(void *)Thread2,NULL);
pthread_create(&ppid1,&attr1,(void *)Thread1,NULL);
pthread_join(ppid3,NULL);
pthread_join(ppid2,NULL);
pthread_join(ppid1,NULL);
pthread_attr_destroy(&attr2);
pthread_attr_destroy(&attr1);
return 0;
}
在这个程序中,我创建了一个具有默认属性的线程和两个调度策略为SCHED_RR和特定优先级的线程。我的问题是: 当我 运行 程序时,我几乎看不到线程 1 的输出。这是怎么发生的? 我认为线程 1 和线程 2 是实时进程,线程 3 是普通进程。 所以线程 3 永远不会 运行 直到线程 1 和线程 2 退出。但是在我的程序中线程1和线程2永远不会退出,所以我预计实际上只有线程2可以运行。 为什么我能看到线程2和线程3的输出,而看不到线程1的输出?
以下建议代码:
- 它只检查系统函数的一些错误状态值
- 显示 OP 出现问题的原因
- 遵循公理:每行只有一个语句,每个语句(最多)一个变量声明。
- 更正了编译器在 OP 代码中指出的许多问题
注意:这是 运行 ubuntu linux 16.04
#include <stdio.h>
//#include <unistd.h> -- contents not used
#include <stdlib.h>
#include <pthread.h>
void *Thread1( void *data );
void *Thread2( void *data );
void *Thread3( void *data );
void *Thread1( void *data )
{
(void)data;
sleep(1);
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 1 \n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
for( size_t i=0; i<1000; i++ )
{
printf("thread 1\n");
}
printf("Pthread 1 exit\n");
pthread_exit( NULL );
}
void *Thread2( void *data )
{
(void)data;
sleep(1);
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( size_t i = 0; i< 1000; i++ )
{
printf("thread 2\n");
}
printf("Pthread 2 exit\n");
pthread_exit( NULL );
}
void *Thread3( void *data )
{
(void)data;
sleep(1);
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( size_t i = 0; i<1000; i++ )
{
printf("thread 3\n");
}
printf("Pthread 3 exit\n");
pthread_exit( NULL );
}
int main( void )
{
unsigned 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;
pthread_t ppid2;
pthread_t ppid3;
struct sched_param param;
pthread_attr_t attr3;
pthread_attr_t attr1;
pthread_attr_t attr2;
pthread_attr_init(&attr1);
pthread_attr_init(&attr3);
pthread_attr_init(&attr2);
param.sched_priority = 97;
pthread_attr_setschedpolicy(&attr1,SCHED_RR);
pthread_attr_setschedparam(&attr1,¶m);
pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);
param.sched_priority = 98;
pthread_attr_setschedpolicy(&attr2,SCHED_RR);
pthread_attr_setschedparam(&attr2,¶m);
pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);
int create3 = pthread_create( &ppid3, &attr3, Thread3, NULL );
if( create3 )
{
fprintf( stderr, "pthread_create for thread 3 failed with status: %d\n", create3 );
//exit( EXIT_FAILURE );
}
int create2 = pthread_create( &ppid2, &attr2, Thread2, NULL );
if( create2 )
{
fprintf( stderr, "pthread_create for thread 2 failed with status: %d\n", create2 );
//exit( EXIT_FAILURE );
}
int create1 = pthread_create( &ppid1, &attr1, Thread1, NULL );
if( create1 )
{
fprintf( stderr, "pthread_create for thread 1 failed with status: %d\n", create1 );
//exit( EXIT_FAILURE );
}
pthread_join(ppid3,NULL);
pthread_join(ppid2,NULL);
pthread_join(ppid1,NULL);
pthread_attr_destroy(&attr3);
pthread_attr_destroy(&attr2);
pthread_attr_destroy(&attr1);
return 0;
}
运行以普通用户身份运行程序会导致:
The current user is not root
pthread_create for thread 2 failed with status: 1
pthread_create for thread 1 failed with status: 1
SCHED_OTHER
thread 3 <-- repeats 1000 times
Pthread 3 exit
运行以 root 身份运行程序会导致:
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
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
SCHED_OTHER
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 2
SCHED_RR 1
thread 1
thread 1
thread 2
thread 3
thread 3
thread 3
thread 2
thread 1
thread 1
thread 1
thread 1
thread 1
... continues for a total of 3000 lines and
... as each thread completes it outputs:
pthread 1 exit -OR- pthread 2 exit -OR- pthread 3 exit
回答 OP 问题:
每次实时线程调用 printf()
时,其他线程都有机会 运行。部分原因是执行了上下文切换,包括在用户和 OS 进程之间切换的上下文切换。
线程 3 可以是 运行 因为 0.05s 是为非 运行 时间任务保留的,通过 echo -1 > /proc/sys/kernel/sched_rt_runtime_us
:
The default values for
sched_rt_period_us
(1000000 or 1s) andsched_rt_runtime_us
(950000 or 0.95s). This gives 0.05s to be used bySCHED_OTHER
(non-RT tasks). These defaults were chosen so that a run-away realtime tasks will not lock up the machine but leave a little time to recover it. By setting runtime to -1 you'd get the old behaviour back.
线程1不能是运行因为线程2有更高的优先级(注意99是pthread调用中最高的RT优先级,这与内部Linux编号相矛盾并解释here), round-robin调度只在具有相同优先级的进程队列中执行:
SCHED_RR
tasks are scheduled by priority, and within a certain priority they are scheduled in a round-robin fashion. EachSCHED_RR
task within a certain priority runs for its allotted timeslice, and then returns to the bottom of the list in its priority array queue.
Understanding the Linux 2.6.8.1 CPU Scheduler
关于如何找出发生这种情况的原因的一些说明。为此,我们需要源代码和动态跟踪器,例如 SystemTap。通过 scheduler.ctxswitch
探测器切换线程(或更准确地说 上下文切换 )can be traced,它是 sched_switch
跟踪点的包装器。
检查跟踪点周围的源代码表明新任务由调用 pick_next_task
:
__schedule
函数处理
3392 next = pick_next_task(rq, prev, cookie);
...
3397 if (likely(prev != next)) {
...
3402 trace_sched_switch(preempt, prev, next);
爬取源代码将我们引向 pick_next_task_rt
,在某些情况下 returns NULL 而不是我们的线程。 SystemTap 时间到了!
# stap -e 'probe kernel.function("pick_next_task_rt").return {
if ($return == 0) {
println($rq->rt$) } }' -c ./a.out
...
{.active={...}, .rt_nr_running=2, .highest_prio={...}, .rt_nr_migratory=2, .rt_nr_total=2,
.overloaded=1, .pushable_tasks={...}, .rt_throttled=1, .rt_time=950005330, .rt_runtime=950000000,
.rt_runtime_lock={...}, .rt_nr_boosted=0, .rq=0xffff8801bfc16c40,
.leaf_rt_rq_list={...}, .tg=0xffffffff81e3d480}
SCHED_OTHER
因此,似乎 rt_time
大于 950 毫秒,并且当我们切换到 SCHED_OTHER
时设置了 rt_throttled
标志。进一步谷歌搜索导致 this answer 和上面链接的文档。