Linux线程调度策略以及优先级实验(图文)

Linux线程调度策略以及优先级实验

什么是线程调度策略?

Linux内核共有三种调度算法,他们分别是:

1、SCHED_OTHER 分时调度策略,
2、SCHED_FIFO实时调度策略,先到先服务
3、SCHED_RR实时调度策略,时间片轮转

其中,SCHED_FIFO与SCHED_RR属于实时策略,SCHED_OTHER属于分时策略。
实时策略线程将得到优先调用,实时策略线程根据实时优先级决定调度权值,分时策略线程则通过nice和counter值决定权值,nice越小,counter越大,被调度的概率越大,也就是曾经使用了cpu最少的线程将会得到优先调度。

三种调度策略

分时调度策略

SCHED_OTHER 分时调度策略:
非实时的,无法设置优先级

实时调度策略

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

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

调度策略组合情况

所有任务都采用linux分时调度策略(SCHED_OTHER)时:
创建时指定优先级nice值,根据nice值确定在cpu上的执行时间(counter),对每个任务动态优先级的计算(counter+20-nice)结果去选择运行,当这 个时间片用完后(counter减至0)或者主动放弃cpu时,该任务被放在就绪队列末尾(时间片用完)或等待队列(因等待资源而放弃cpu)中。

所有任务都采用FIFO时:
优先级高的先运行,并且该任务将一直占有CPU直到优先级更高的任务就绪或者主动放弃。同优先级先入队列先运行。

所有任务都采用RR时
综合了前两种策略,优先级高的先运行,优先级相同共分时间片,用完时间片的去就绪队列尾。

任务中同时含有实时和分时时
当实时进程准备就绪后,如果当前cpu正在运行非实时进程,则实时进程立即抢占非实时进程。

测试实验

主要目的时测试在不同的调度策略以及不同的优先级设定的状况下,线程的抢占情况。

测试方法主要为在设定线程策略与优先级后,创建三个线程,观察它们的log输出情况以及使用busybox top查看CPU占用情况。

修改线程属性的代码部分如下:

    param1.sched_priority = 40;                            //修改优先级 
    pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);       
    pthread_attr_setschedpolicy(&attr1,SCHED_FIFO);        //修改调度策略
    if(0!=pthread_attr_setschedparam(&attr1,&param1))
    {
        printf("setschedpolicy attr1 NG! \n");
    }

实验全部代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#if 1
void *Thread1(void* pp)
{
  sleep(1);
  int i;
  int policy;
  struct sched_param param;
  pthread_getschedparam(pthread_self(),&policy,&param);
  switch(policy)
  {
  case SCHED_OTHER:
      printf("SCHED_OTHER 1\n");
      break;
  
  case SCHED_RR:
      printf("SCHED_RR 1 \n");
      break;
  
  case SCHED_FIFO:
      printf("SCHED_FIFO 1\n");
      break;
  }
  
while(1)
{
    for(i=1;i<5000000;i++)
    {
    
    
    }
    printf("Pthread 1\n");
    //usleep(500);    
}
  printf("Pthread 1 exit\n");
}

void *Thread2(void* pp)
{
  sleep(2);
  int i;
  int policy;
  struct sched_param param;
  pthread_getschedparam(pthread_self(),&policy,&param);
    switch(policy)
  {
  case SCHED_OTHER:
      printf("SCHED_OTHER 2\n");
      break;
  
  case SCHED_RR:
      printf("SCHED_RR 2 \n");
      break;
  
  case SCHED_FIFO:
      printf("SCHED_FIFO 2\n");
      break;
  }
while(1)
{
    for(i=1;i<5000000;i++)
    {
     
    
    }
    printf("Pthread 2\n");
    //usleep(500);
}
  printf("Pthread 2 exit\n");
}

void *Thread3(void* pp)
{
  sleep(3);
  int i;
  int policy;
  struct sched_param param;
  pthread_getschedparam(pthread_self(),&policy,&param);
    switch(policy)
  {
  case SCHED_OTHER:
      printf("SCHED_OTHER 3\n");
      break;
  
  case SCHED_RR:
      printf("SCHED_RR 3 \n");
      break;
  
  case SCHED_FIFO:
      printf("SCHED_FIFO 3\n");
      break;
  }
while(1)
{
    for(i=1;i<5000000;i++)
    {
     
    
    }
    printf("Pthread 3\n");
    //usleep(500);
}
  printf("Pthread 3 exit\n");
}
#endif

int main()
{
    int uid;
    uid = getuid();
    if(uid==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 param1;
    struct sched_param param2;
    struct sched_param param3;

    pthread_attr_t attr1,attr2,attr3;

    pthread_attr_init(&attr1);
    pthread_attr_init(&attr2);
    pthread_attr_init(&attr3);
          
    param1.sched_priority = 40;
    pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setschedpolicy(&attr1,SCHED_OTHER);
    if(0!=pthread_attr_setschedparam(&attr1,&param1))
    {
        printf("setschedpolicy attr1 NG! \n");
    }
    

    param2.sched_priority = 20;
    pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setschedpolicy(&attr2,SCHED_RR);
    pthread_attr_setschedparam(&attr2,&param2);
    if(0!=pthread_attr_setschedparam(&attr2,&param2))
    {
        printf("setschedpolicy attr2 NG! \n");
    }    

    param3.sched_priority = 20;
    pthread_attr_setinheritsched(&attr3,PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setschedpolicy(&attr3,SCHED_RR);
    pthread_attr_setschedparam(&attr3,&param3);
    if(0!=pthread_attr_setschedparam(&attr3,&param3))
    {
        printf("setschedpolicy attr3 NG! \n");
    }    

    pthread_create(&ppid1,&attr1,Thread1,NULL);
    
    pthread_create(&ppid2,&attr2,Thread2,NULL);
    
    pthread_create(&ppid3,&attr3,Thread3,NULL);

    pthread_join(ppid1,NULL);
    pthread_join(ppid2,NULL);
    pthread_join(ppid3,NULL);    
    //while(1) {           
        //sleep(100);
        //printf("main loop\n");
    //}
    
    pthread_attr_destroy(&attr1);
    pthread_attr_destroy(&attr2);
    pthread_attr_destroy(&attr3);
    return 0;
}

实验过程现象

SCHED_OTHER

创建三个分时线程:
Linux线程调度策略以及优先级实验(图文)_第1张图片因分时策略不能设置优先级,所以不进行优先级不同的测试。
实验结果如下:
Linux线程调度策略以及优先级实验(图文)_第2张图片
Linux线程调度策略以及优先级实验(图文)_第3张图片
在这里插入图片描述

SCHED_FIFO

创建三个实时FIFO线程,且它们三个的优先级相同,皆为30。
实验结果如下:

Linux线程调度策略以及优先级实验(图文)_第4张图片
Linux线程调度策略以及优先级实验(图文)_第5张图片
Linux线程调度策略以及优先级实验(图文)_第6张图片

在这里插入图片描述

SCHED_RR

创建三个实时RR线程:
Linux线程调度策略以及优先级实验(图文)_第7张图片
且它们三个的优先级相同,皆为30。
实验结果如下:
Linux线程调度策略以及优先级实验(图文)_第8张图片
Linux线程调度策略以及优先级实验(图文)_第9张图片
在这里插入图片描述

全为实时且不同优先级

创建三个实时线程,优先级不同:
Linux线程调度策略以及优先级实验(图文)_第10张图片
Linux线程调度策略以及优先级实验(图文)_第11张图片
Linux线程调度策略以及优先级实验(图文)_第12张图片
在这里插入图片描述

分时实时同时存在

创建两个实时/分时线程,优先级不同,实验结果如下:
Linux线程调度策略以及优先级实验(图文)_第13张图片
Linux线程调度策略以及优先级实验(图文)_第14张图片
Linux线程调度策略以及优先级实验(图文)_第15张图片
Linux线程调度策略以及优先级实验(图文)_第16张图片
在这里插入图片描述

实验结论

实验结论:
1、三种调度策略线程满足自身策略特性。
2、实时线程无条件抢占分时线程,分时线程无法抢占实时线程。
3、实时线程中,高优先级线程抢占低优先级线程。
4、实时线程中,高优先级线程运行中不会被低优先级线程所打断。

实验课题(以下说明并未在实验中测出):
linux有一个组策略就是分配实时和分时的时间片
sysctl -n kernel.sched_rt_period_us # 实时进程调度的单位CPU时间 1 秒
1000000
sysctl -n kernel.sched_rt_runtime_us # 实时进程在 1 秒中实际占用的CPU时间, 0.95秒
950000
这个设置说明实时进程在运行时并不是完全占用CPU的, 每1秒中有0.05秒的时间可以给其它进程运行.
这样既不会对实时进程的响应时间造成太大的影响, 也避免了实时进程卡住时导致整个系统无响应.

你可能感兴趣的:(Linux,线程,linux,多线程,c语言)