精华内容
参与话题
问答
  • 最近研发的产品出了点小bug,最后查到根本原因是,其中一个进程A使用基于FIFO的实时进程优先级,而另一个进程B是使用普通调度的进程优先级,而A和B两个进程是互相通信的,进程B会被饿死,而进程A也不能正常工作。...

     

    前言

    出处@https://www.cnblogs.com/qinwanlin/p/8631185.html

    最近研发的产品出了点小bug,最后查到根本原因是,其中一个进程A使用基于FIFO的实时进程优先级,而另一个进程B是使用普通调度的进程优先级,而A和B两个进程是互相通信的,进程B会被饿死,而进程A也不能正常工作。分析问题过程中查找了一些资料,以下记录一些特别注意的点。

    Linux进程调度的三种策略

    (1)SCHED_OTHER,分时调度策略

    (2)SCHED_FIFO,实时调度策略,先到先服务

    (3)SCHED_RR,实时调度策略,时间片轮转 

    由于相关内容比较多,本人也末必比别人讲得更清楚,关于进程调度更详细的内容建议读《深入理解Linux内核》,网上的很多内容都是从此而来,也不一定比这本书讲得好。另可参考此链接

    https://blog.csdn.net/maximuszhou/article/details/42042161

    前面遇到bug的进程A就是使用SCHED_FIFO调度策略的,而进程B没有经过设置,默认是SCHED_OTHER。

    如何设置为实时进程

    查找资料的时候发现有个链接问,为什么设置FIFO策略,但和预想的不一致。链接在此 http://ask.csdn.net/questions/254095

    从代码看是因为设置的方法不对,直接上代码,可以设置进程和线程的调度策略
     

    复制代码

     1  #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <pthread.h>
     4 #include <sched.h>
     5 
     6 
     7 pid_t pid = getpid();
     8 struct sched_param param;
     9 param.sched_priority = sched_get_priority_max(SCHED_FIFO);   // 也可用SCHED_RR
    10 sched_setscheduler(pid, SCHED_RR, &param);                   // 设置当前进程
    11 pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);   // 设置当前线程

    复制代码

    可以通过top命令查看进程是否成功,如果为"rt"表示是实时进程了。如果不成功,可能是权限问题,需要roo权限。

    调整进程优先级

     如果不调整调度策略,也可以提升进程优先级,使得进程得到更多的CPU,特别是交互式程序,用户体检更好。代码很简单,只需要调用nice(int n)函数即可。n的有效范围是-20~19,数值越小表示优先级越高。具体内容不在此复制粘贴,还是看《深入理解Linux内核》比较靠谱。

     

    浅析Linux线程调度

         在Linux中,线程是由进程来实现,线程就是轻量级进程( lightweight process ),因此在Linux中,线程的调度是按照进程的调度方式来进行调度的,也就是说线程是调度单元。Linux这样实现的线程的好处的之一是:线程调度直接使用进程调度就可以了,没必要再搞一个进程内的线程调度器。在Linux中,调度器是基于线程的调度策略(scheduling policy)和静态调度优先级(static scheduling priority)来决定那个线程来运行。

        对于下面三种调度策略SCHED_OTHER, SCHED_IDLE, SCHED_BATCH,其调度优先级sched_priority是不起作用的,即可以看成其调度优先级为0;调度策略SCHED_FIFO和SCHED_RR是实时策略,他们的调度值范围是1到99,数值越大优先级越高,另外实时调度策略的线程总是比前面三种通常的调度策略优先级更高。通常,调度器会为每个可能的调度优先级(sched_priority value)维护一个可运行的线程列表,并且是以最高静态优先级列表头部的线程作为下次调度的线程。所有的调度都是抢占式的:如果一个具有更高静态优先级的线程转换为可以运行了,那么当前运行的线程会被强制进入其等待的队列中。下面介绍几种常见的调度策略:

        SCHED_OTHER:该策略是是默认的Linux分时调度(time-sharing scheduling)策略,它是Linux线程默认的调度策略。SCHED_OTHER策略的静态优先级总是为0,对于该策略列表上的线程,调度器是基于动态优先级(dynamic priority)来调度的,动态优先级是跟nice中相关(nice值可以由接口nice, setpriority,sched_setattr来设置),该值会随着线程的运行时间而动态改变,以确保所有具有SCHED_OTHER策略的线程公平运行。在Linux上,nice值的范围是-20到+19,默认值为0;nice值越大则优先级越低,相比高nice值(低优先级)的进程,低nice值(高优先级)的进程可以获得更多的处理器时间。使用命令ps -el查看系统的进程列表,其中NI列就是进程对应的nice值;使用top命令,看到的NI列也是nice值。运行命令的时候可用nice –n xx cmd来调整cmd任务的nice值,xx的范围是-20~19之间。

        SCHED_FIFO:先入先出调度策略(First in-first out scheduling)。该策略简单的说就是一旦线程占用cpu则一直运行,一直运行直到有更高优先级任务到达或自己放弃。

        SCHED_RR:时间片轮转调度(Round-robin scheduling)。该策略是SCHED_FIFO基础上改进来的,他给每个线程增加了一个时间片限制,当时间片用完后,系统将把该线程置于队列末尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平。使用top命令,如果PR列的值为RT,则说明该进程采用的是实时策略,即调度策略是SCHED_FIFO或者为SCHED_RR,而对于非实时调度策略(比如SCHED_OTHER)的进程,该列的值是NI+20,以供Linux内核使用。我们可以通过命令:

     

    ps -eo state,uid,pid,ppid,rtprio,time,comm

     

    来查看进程对应的实时优先级(位于RTPRIO列下),如果有进程对应的列显示“-”,则说明它不是实时进程。注意任何实时策略进程的优先级都高于普通的进程,也就说实时优先级和nice优先级处于互不相交的两个范畴。

     

        在Linux中,与调度相关的常见接口如下:

     

    
     
    1. #include <sched.h>

    2. int sched_get_priority_max(int policy);

     

    该接口获取指定调度策略可以设置的最大优先级,类似的 sched_get_priority_min接口获取调度策略可以设置的最小优先级。在Linux中,对于SCHED_FIFO和SCHED_RR调度策略其优先级为1到99,其他调度策略优先级为0。注意在不同系统上,这个优先级范围可能不一样。

     

    
     
    1. #include <pthread.h>

    2. int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);

     

    该接口可以用来设置线程的调度策略,即设置线程属性attr。参数policy可以是CHED_FIFO, SCHED_RR和SCHED_OTHER。系统创建线程时,默认的线程调度策略是SCHED_OTHER。类似可以通过接口

     

    int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)

     

    获取线程的调度策略。

     

    
     
    1. #include <pthread.h>

    2. int pthread_attr_setschedparam(pthread_attr_t *attr,

    3. const struct sched_param *param);

     

    该接口可以用来设置线程的调度优先级。结构sched_param定义如下:

     

    
     
    1. struct sched_param {

    2. int sched_priority; /* Scheduling priority */

    3. };

     

    类似的的接口,可以用来获取线程调度的优先级:

     

    
     
    1. int pthread_attr_getschedparam(const pthread_attr_t *attr,

    2. struct sched_param *param);

    
     
    1. #include <sched.h>

    2. int sched_yield(void);

     

    调用该接口可以使得当前线程主动交出CPU,并把该线程放到相应调度队列的末尾。如果当前线程是最高优先级队列中唯一的线程,则在调用sched_yield后,该线程继续保持运行。

     

    
     
    1. #include <sched.h>

    2. int sched_setaffinity(pid_t pid,

    3. size_t cpusetsize,const cpu_set_t *mask);

     

    该接口可以用来设置线程的CPU亲和性(CPU affinity),设置线程的亲和性可以使得线程绑定到一个或多个指定的CPU上运行。在多处理器系统上,设置CPU亲和性可以提高性能(主要原因是尽可能避免了cache失效和切换到其他CPU的消耗)。CPU亲和性掩码是由cpu_set_t结果来实现的,该结构体需要用预定义好的宏来操作;参数pid是指定线程的TID,可以通过gettid()来获取,即线程在内核中对应进程id,若pid为0,则设置的是调用线程的CPU亲和性,注意用getpid()获取的是主线程的id;参数cpusetsize的值通常是mask的大小,即sizeof(mask)。除了这个接口外,设置线程亲和性接口还有:

     

    
     
    1. #include <pthread.h>

    2. int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize,

    3. const cpu_set_t *cpuset);

    4. int pthread_attr_setaffinity_np(pthread_attr_t *attr,

    5. size_t cpusetsize, const cpu_set_t *cpuset);

     

    通过fork创建的子进程继承父进程的CPU亲和性,通过 execve()后,亲和性仍然保持不变。我们可以下面命令来查看多核cpu的负载:

        I)cat /proc/cpuinfo  查看所有cpu的信息;

        II)top命令,然后再输入1,则显示多个cpu的使用信息;

        III)top命令,然后按下f,进入top Current Fields设置页面,然后按下j,表示要求显示进程使用那个cpu,回车后,回到刚才界面,此时P 显示此进程使用哪个CPU。

     

        下面是测试代码:

     

    
     
    1. #include <stdio.h>

    2. #include <pthread.h>

    3. #include <sched.h>

    4. #include <assert.h>

    5.  
    6. static int get_thread_policy(pthread_attr_t *attr)

    7. {

    8. int policy;

    9. int rs = pthread_attr_getschedpolicy(attr,&policy);

    10. assert(rs==0);

    11.  
    12. switch(policy)

    13. {

    14. case SCHED_FIFO:

    15. printf("policy=SCHED_FIFO\n");

    16. break;

    17.  
    18. case SCHED_RR:

    19. printf("policy=SCHED_RR\n");

    20. break;

    21.  
    22. case SCHED_OTHER:

    23. printf("policy=SCHED_OTHER\n");

    24. break;

    25.  
    26. default:

    27. printf("policy=UNKNOWN\n");

    28. break;

    29. }

    30. return policy;

    31. }

    32.  
    33. static void show_thread_priority(pthread_attr_t *attr,int policy)

    34. {

    35. int priority = sched_get_priority_max(policy);

    36. assert(priority != -1);

    37. printf("max_priority=%d\n",priority);

    38.  
    39. priority= sched_get_priority_min(policy);

    40. assert(priority != -1);

    41. printf("min_priority=%d\n",priority);

    42. }

    43.  
    44. static int get_thread_priority(pthread_attr_t *attr)

    45. {

    46. struct sched_param param;

    47. int rs = pthread_attr_getschedparam(attr,¶m);

    48. assert(rs == 0);

    49.  
    50. printf("priority=%d\n",param.__sched_priority);

    51. return param.__sched_priority;

    52. }

    53.  
    54. static void set_thread_policy(pthread_attr_t *attr,int policy)

    55. {

    56. int rs = pthread_attr_setschedpolicy(attr,policy);

    57. assert(rs==0);

    58. }

    59.  
    60. int main(void)

    61. {

    62. pthread_attr_t attr;

    63. int rs;

    64.  
    65. rs = pthread_attr_init(&attr);

    66. assert(rs==0);

    67.  
    68. int policy = get_thread_policy(&attr);

    69.  
    70. printf("Show current configuration of priority\n");

    71. get_thread_policy(&attr);

    72. show_thread_priority(&attr,policy);

    73.  
    74. printf("show SCHED_FIFO of priority\n");

    75. show_thread_priority(&attr,SCHED_FIFO);

    76.  
    77. printf("show SCHED_RR of priority\n");

    78. show_thread_priority(&attr,SCHED_RR);

    79.  
    80. printf("show priority of current thread\n");

    81. get_thread_priority(&attr);

    82.  
    83. printf("Set thread policy\n");

    84.  
    85. printf("set SCHED_FIFO policy\n");

    86. set_thread_policy(&attr,SCHED_FIFO);

    87. get_thread_policy(&attr);

    88. get_thread_priority(&attr);

    89.  
    90. printf("set SCHED_RR policy\n");

    91. set_thread_policy(&attr,SCHED_RR);

    92. get_thread_policy(&attr);

    93.  
    94. printf("Restore current policy\n");

    95. set_thread_policy(&attr,policy);

    96. get_thread_priority(&attr);

    97.  
    98. rs = pthread_attr_destroy(&attr);

    99. assert(rs==0);

    100.  
    101. return 0;

    102. }

     

    编译和运行程序结果如下:

     

    
     
    1. $gcc -Wall -lpthread hack_thread_sched.c -o hack_thread_sched

    2. $./hack_thread_sched

    3. policy=SCHED_OTHER

    4. Show current configuration of priority

    5. policy=SCHED_OTHER

    6. max_priority=0

    7. min_priority=0

    8. show SCHED_FIFO of priority

    9. max_priority=99

    10. min_priority=1

    11. show SCHED_RR of priority

    12. max_priority=99

    13. min_priority=1

    14. show priority of current thread

    15. priority=0

    16. Set thread policy

    17. set SCHED_FIFO policy

    18. policy=SCHED_FIFO

    19. priority=0

    20. set SCHED_RR policy

    21. policy=SCHED_RR

    22. Restore current policy

    23. priority=0

     

    从输出结果,我们可以看到:

        I)线程默认的调度策略为SCHED_OTHER,并且最大和最小调度优先级都是0。

        II)调度策略SCHED_FIFO和SCHED_RR的优先级范围为1到99,并且初始设置时对应的调度优先级初始值为0。

        在Linux中,调度程序是一个叫schedule()的函数,该函数调用的频率很高,由它来决定是否要执行进程的切换,如果要切换的话,切换到那个进程等。那么在Linux中,在什么情况下要执行这个调度程序呢?我们把这种情况叫作调度时机。Linux调度时机主要有:

       I)进程状态转换的时刻:进程终止、进程睡眠(比如I/O阻塞就会导致这种情况),还比如进程调用sleep()或exit()等函数进行状态转换。 

       II)当前进程的时间片用完时。

         III)设备驱动程序,当设备驱动程序执行长而重复的任务时,在每次反复循环中,驱动程序读检查是否需要调度,如果必要,则调用调度程序schedule()放弃CPU。

         IV)进程从中断、异常及系统调用返回到用户态时。

     

     

    展开全文
  • linux 进程优先级

    千次阅读 2018-09-16 18:42:02
    Linux 中进程优先级绝不是如想象中的那么简单,相反它的概念比较混杂,它甚至不是很符合直觉。 Linux 进程优先级跟随调度算法的不断发展,其意义在不同的阶段也有着不同的含义,所以本来想从 Linux 的调度...

    [Github pages]

    Linux 中进程的优先级绝不是如想象中的那么简单,相反它的概念比较混杂,它甚至不是很符合直觉。

    Linux 进程的优先级跟随调度算法的不断发展,其意义在不同的阶段也有着不同的含义,所以本来想从 Linux 的调度发展史写起,但是无奈那一部分的涉猎不是很深入。不管怎样,发展到最后,结果是 Linux 系统可以在同一个系统上扩展多个调度算法,于是在同一个系统上面优先级也有了不同的含义,本文只对较新的 Linux 系统(截止4.4)的优先级做一个基本介绍,这个过程需要逐步深入,前面的一坨看起来与优先级不相关的东西并不是废话,别说话,耐心看。

    字义上的优先级

    所谓优先级就字面的意思来看就是事情的紧急程度,虽说有一个先来后到的说法,但是优先级则打破了这一规则。在可抢占的操作系统上面,高优先级的进程可以在后来者的情况下优先占据 cpu 的使用权,而更低优先级的进程则只能选择被动出让 cpu,无论其是否心甘情愿,也就是不管它的事情有咩有完成,都得让路给高优先级的进程(VIP)。

    通常意义上来讲,我们平时说优先级也正是指的上面字面意义上的优先级,代表对 cpu 的优先使用级别,高优先级的进程先使用,低优先级的进程后使用。对于没有时间片限制的一些调度算法来说,只有最高优先级的进程主动让出 cpu(完成它自己的工作),次低一点优先级的进程才可以获取 cpu 使用权。而对于有时间片限制的调度算法,优先级高的进程则代表它优先、较多地享有 cpu 使用权,注意:优先、较多。它意味着可能不等到高优先级任务主动出让 cpu,就会被强制切换到更低一点优先级的进程,但是总体来说,高优先级的进程会有比其它进程更多的 cpu 使用时间。

    Linux 系统的调度类

    1. 实时调度类
      Linux 上面的实时调度不是硬实时的,而是尽可能的实时,比如 SCHED_RRSCHED_FIFO 两种,采用 RT 调度算法。但是估计是这种实时调度策略只能够在某些特定的场景下发挥作用,而有一些对周期要求比较严格的场景,比如多媒体数据流,则无法满足。于是后续出台了更的实时调度策略,它就是 SCHED_DEADLINE,采用 EDF 调度算法,不过说实话,这种调度类我一直没能够驾驭得了,用上去效果总是不如预期,还是自己功力不足,有待进一步调教。
    2. 非实时调度类
      就是大名鼎鼎的完全公平调度 CFS(Completely fair schedule)。在内核定义中是 SCHED_OTHER 或者 SCHED_NORMAL,这两个代表同样的含义。还有 SCHED_BATCHSCHED_IDLE 这两种,不过不是很常用,不过他们同属于 CFS 调度算法,也就是说它们的优先级概念是一样的。

    Linux 上面的调度类主要就是这几个了,还有一类叫做 SCHED_ISO,不过在内核里面作为保留字段,并没有实现。其中实时调度类使用 RT 调度算法,不过实时类的 SCHED_DEADLINE 调度类是 EDF 调度算法,非实时的调度类就是 CFS 调度算法了,可以推知,在 Linux 系统上面有三种优先级的概念,它们分别归属于不同的调度算法上,如下图所示:

    调度算法分类

    内核角度看优先级

    在内核里面 task_struct 用于描述进程的各个属性,属于进程的结构体抽象,其中有几个字段如下:

    struct task_struct {
    	... ...
    	int prio, static_prio, normal_prio;
    	unsigned int rt_priority;
    	... ...
    }
    

    可以看到内核里面的优先级有一坨,分别记录为:

    • prio:动态优先级。,该值使用 effective_prio 函数进行计算,在 CFS 类或者 EDF 类的调度策略中与 normal_prio 是一致的,在 RT 策略当中就直接返回当前的动态优先级值(其值与静态优先级相同),该值主要是用于在运行过程中动态改变程序优先级的值,保证调度的公平性,低优先级的进程在长时间得不到运行状况下会暂时调高其动态优先级,这个计算过程比较复杂,这里不深入。
    • static_prio:静态优先级。只有 CFS 类的才有静态优先级,其他的类在内核当中也为其设置了该成员,但是并没有实际的物理意义,**也就是静态优先级只有在 CFS 类中才有其实际的作用,其它的只是个幌子。**该值的计算方式是通过一个宏定义来完成:#define NICE_TO_PRIO(nice) ((nice) + DEFAULT_PRIO),展开之后就是 nice + (100+(19-(-20)+1)/2)
    • normal_prio:归一化优先级。所谓归一化就是统一的意思,因为对于不同的调度类来说,它们的优先级的概念是不一样的,但是对于内核来说,它需要一个简单的概念来区分归根结底到底是谁的优先级更高一点。可以理解为不同的调度类优先级就是不同国家的货币,归一化优先级就是黄金,把不同国家的货币(不同调度类)转换为等量黄金,之后才能够比较到底谁才是土豪(谁拥有优先调度权)。
    • rt_priority:RT 调度算法类的优先级,其值与用户空间传进来的值一致(用户空间使用 sched_setparam 等函数传递),取值范围 1~99.

    在内核的 INIT_TASK 宏定义中可以看到上面三个值初始化默认都是 MAX_PRIO-20,也就是 120.后面有一张表列出了不同调度类情况下的归一化优先级的计算方法与值的范围。内核里面的归一化优先级值越小,代表实际优先级越高,目前最小的值是 -1

    DEADLINE 调度类

    该调度类在目前的 Linux 内核里面属于优先级最高的调度类,也就是说假设系统上面存在多个调度类,那么每次重新调度的时候,都是先从该调度类下面去找到一个可以投入运行的进程进行调度。归属于该调度类的进程其归一化优先级都是 -1,在该调度类内部不再区分多个优先级,统一归为 -1.

    如果要切换某一个进程的调度类到 DEADLINE,那么就采用 sched_setattr 函数进行设置,大概的方式如下(由于本文章不讨论调度类的使用与原理,此处简略若干):

    struct sched_attr attr;
    
    memset(&attr, 0, sizeof(attr));
    attr.size = sizeof(attr);
    
    /* This creates a 200ms / 1s reservation */
    attr.sched_policy = SCHED_DEADLINE;
    attr.sched_runtime = 20*1000*1000;
    attr.sched_deadline = attr.sched_period = 33*1000*1000;
    ret = sched_setattr(0, &attr, flags);
    

    内核里面关于该调度类优先级的一个宏定义是:MAX_DL_PRIO,它的值是0,转换为归一化优先级就是 -1.目前为止,这个归一化优先级值的优先级最高。

    FIFO、RR 等 RT 调度类

    从内核的定义中可以看到宏定义:`

    #define MAX_USER_RT_PRIO	100
    #define MAX_RT_PRIO		MAX_USER_RT_PRIO
    

    可以看到它的优先级最大是 100,转换之后就是 99(内核要减去1),也就是 RT 类型的调度类优先级范围在 0~99 之间,该调度类可以采用 sched_setparam 函数来完成优先级的设置,该函数的参数是 pid 号与一个叫做 sched_param 的结构体,该结构体只有一个参数,那就是优先级的值,该值越大(用户空间值越大优先级越高)表示优先级越高,范围是 1~99,需要注意的是从内核的角度来看归一化优先级的值越小,优先级才越高,也就是说用户在 user 空间设置的这个值是与内核里面的值是翻转着来的。

    上面 task_struct->rt_priority 成员的值就是 sched_setparam 函数第二个参数的 sched_priority 成员传递的值。

    CFS 调度类

    主要就是 NORMAL/OTHER,BATCH 这两种调度类。它们的优先级可以通过 setpriority 函数来进行设置,可以设置的范围是 -20~19,需要注意的是这个范围指的是 nice 值,它与优先级有一定的区别(详情参考后面),分别对应内核里面的归一化优先级 100~139.

    在 CFS 调度算法中,优先级并不会特别大地影响到程序被调用的先后顺序,在这种调度算法当中,优先级影响最大的是 cpu 使用时间,优先级越高可以占有的 cpu 使用时间就相对越多。所以如果拼命提高某些进程的优先级,最后发现它的实时性还不是很好,那不是因为优先级失效了,而是因为使用不当,要想提高程序的响应速度与实时性,最好是将它设置为 RT 调度类。

    上述的有些调度类如果是在 ubuntu 桌面版上面做的实验,有些可能是不起作用的,因为 ubuntu 系统对非 root 用户的权限做了限制,比如优先级减少不能增加,调度类也不能随意更换(内核相关的选项没有被编译进去等),切换到 root 用户就可以正确地得到部分实验效果。

    调度类的优先级

    在内核里面,调度类的优先级顺序如下所示:

    SCHED_DEADLINE > SCHED_FIFO/SCHEDRR > SCHED_NORMAl/SCHED_OTHER/SCHED_BATCH > SCHED_IDLE
    

    区分一下调度类的优先级与进程的优先级,调度类包含了归属其下的进程,优先级高的调度类所包含的进程自然会被优先调度,然后在调度类内部才会进一步区分进程的优先级,其中优先级高的调度类中的进程总是会优先于优先级低的调度类中的进程被调度。比较绕,简单说调度顺序的选择有两个层级,调度类是第一层,进程是第二层。

    对于使用同一种调度算法的调度类(RT、EDF、CFS),其调度类的优先级是一样的,实际调度中会在这几个调度类内部找到优先级比较高的进程去进行下一次调度,也就是优先级高的先调度。需要注意的是,就算是属于同一个调度算法的调度类,其实现上也有所不同,进程的调度行为也有所不同(比如 SCHED_RR 与 SCHED_FIFO 的调度行为有所不同),但是优先级的概念一定是统一的。

    看下内核里面是怎样计算归一化优先级的

    static inline int normal_prio(struct task_struct *p)
    {
    	int prio;
    
    	if (task_has_dl_policy(p))
    		prio = MAX_DL_PRIO-1;
    	else if (task_has_rt_policy(p))
    		prio = MAX_RT_PRIO-1 - p->rt_priority;
    	else
    		prio = __normal_prio(p);
    	return prio;
    }
    

    如果是 DEADLINE 调度类,那么它的归一化优先级就是 MAX_DL_PRIO-1,也就是 -1,如果是实时的调度类,它的优先级是 MAX_RT_PRIO-1 - p->rt_priority,范围是 0~98(没有 99 的原因是 rt_priority 的取值范围是 1~99),如果是 CFS 调度类,那么归一化优先级就和静态优先级是相等的,计算公式上面给出过,是一个叫 NICE_TO_PRIO 的宏定义完成计算的,这里再重复下:

    #define MAX_NICE	19
    #define MIN_NICE	-20
    #define NICE_WIDTH	(MAX_NICE - MIN_NICE + 1)
    
    #define MAX_USER_RT_PRIO	100
    #define MAX_RT_PRIO		MAX_USER_RT_PRIO
    
    #define MAX_PRIO		(MAX_RT_PRIO + NICE_WIDTH)
    #define DEFAULT_PRIO		(MAX_RT_PRIO + NICE_WIDTH / 2)
    
    #define NICE_TO_PRIO(nice)	((nice) + DEFAULT_PRIO)
    #define PRIO_TO_NICE(prio)	((prio) - DEFAULT_PRIO)
    

    展开之后就是:静态优先级=nice值+MAX_USER_RT_PRIO+(MAX_NICE - MIN_NICE + 1)/2,带入计算一下就知道范围是 100~139(内核里面的 nice 取值范围是 -20~19).

    调度类 内核归一化优先级范围 user 可设置优先级/NICE范围 设置函数 调度算法
    SCHED_OTHER/NORMAL 100~139 -20~19 sched_setpriority CFS
    SCHED_IDLE 100~139 -20~19 sched_setpriority CFS
    SCHED_BATCH 100~139 -20~19 sched_setpriority CFS
    SCHED_RR 0~98 99~1 sched_setparam RT
    SCHED_FIFO 0~98 99~1 sched_setparam RT
    SCHED_DEADLINE -1 不可设置 sched_setparam EDF

    可以注意到 RT 调度类有一个奇怪的问题,它的范围是 0~98,而不是 0~99,至于它的历史来由是什么我也不清楚,这里只是指出这个现象。另外前期 Linux 对不同的调度类极其优先级有一大堆的不同设置函数,从上表就可以看得出,后来在 DEADLINE 加入之后,估计是开发人员也受不了记忆这么多的函数,于是有了一个万能的函数:sched_setattr,在系统里面可能找不到这个函数实现,使用 __NR_sched_setattr 系统调用号结合 syscall 就可以自行实现,该系统调用的第二个参数 sched_attr 如下所示(不解释了,很容易看懂它是如何统一各个调度类的设置的):

    struct sched_attr {
    	u32 size;
    
    	u32 sched_policy;
    	u64 sched_flags;
    
    	/* SCHED_NORMAL, SCHED_BATCH */
    	s32 sched_nice;
    
    	/* SCHED_FIFO, SCHED_RR */
    	u32 sched_priority;
    
    	/* SCHED_DEADLINE */
    	u64 sched_runtime;
    	u64 sched_deadline;
    	u64 sched_period;
    };
    

    用户空间的 NI,PRI

    除了内核空间里面繁杂、错综的优先级概念,在用户空间也有一些容易混淆的概念,它们之间有着某种联系,这里主要就说用户空间使用 htop 或者 top 命令看到的 NI 与 PRI 值是怎么一回事儿。

    NI 就是 nice 值,顾名思义,就是这个进程的友好程度,越友好的程序 NI 值越大(取值范围 -20~19),也就越慷慨,它们会使用相对较少的 cpu 时间,所谓优先级低;而不那么友好的进程则使用相对较多的 cpu 时间,所谓优先级高。很怀疑起这个名字(nice)这是内核开发者的恶趣味,老实人就一定要慷慨,要付出更多,坏人就可以得到更多。由此可见,nice 值代表了可以使用的 cpu 资源的比例。

    PRI 就是优先级,这个优先级不对应内核里面任何一个优先级的概念,可以看到它的值跟随 NI 值不断变化,在 CFS 调度时关系看起来就像是:PRI = 20+NI。实际上:PRI(new)=PRI(old)+nice,用户空间的进程刚初始化是默认都是 PRI=20,NI=0,当 NI 的值改变的时候,PRI 的值就显而易见。

    在用户空间,我们想要设置某一个进程的 nice 值,那么这个进程一定是 CFS 调度算法下面的调度类,否则无意义,如果想让这个程序尽可能优先的运行,那么通过 nice 值修改可能并不会得到想象中的效果,更好的办法是提升进程的调度类,比如从 SCHED_OTHER 升级到 SCHED_RR。如果想让自己的进程尽可能多地使用 cpu 时间,那么减少 nice 值就是一个很好的选择。

    End

    Linux 里面优先级绝不是那么简单就可以区分的,并且在使用的时候很可能会误用,需要针对内核角度、用户空间角度对优先级有一个全面的了解才能够更好地去使用它。本文的文字比较多,要想更加细致的理解就需要自己动手操作一番,在不同的调度类里面辗转腾挪一波,调调优先级,改改 nice 值就很容易理解这些概念了。

    话说今天珠海刮台风,名曰「山竹」,然而它并不如听上去那么美好,刮起来真的是让人害怕.jpg,「山竹」的级别达到了 17 级,比去年的「天鸽」 14 级更加暴躁,这一天还经历了断电断水,想必明天珠海肯定又是一片狼藉。


    想做的事情就去做吧
    展开全文
  • 调节进程优先级

    2014-05-10 15:32:38
    调节进程优先级,能获取权限,锁定优先级,目前DNF能锁定优先级为高,或者实时
  • Android的进程优先级

    千次阅读 2016-06-23 16:35:24
    android对于所有进程的处理态度都是尽可能不杀死。然而,资源总共就那么多,要是对所有进程都保持宽容的话,资源总会...这个策略就是对所有的进程标记优先级优先级低的先杀死。 android将进程优先级分为5个层次。

    原文作者:Jianan - qinxiandiqi@foxmail.com
    原文地址:http://blog.csdn.net/qinxiandiqi/article/details/51744782
    版本信息:2016-06-23
    版权声明:本文采用CC BY-NC-ND 4.0共享协议。允许复制和转载,但必须在文首显眼位置保留原文作者、原文链接、版本信息、版权声明等信息。不允许演绎和用于商业用途。

    android对于所有进程的处理态度都是尽可能不杀死。然而,资源总共就那么多,要是对所有进程都保持宽容的话,资源总会有消耗殆尽的时候。因此,在内存不足的情况,android系统需要根据一定的策略,选择性的杀死部分进程。这个策略就是对所有的进程标记优先级,优先级低的先杀死。

    android将进程的优先级分为5个层次,按照优先级由高到低排列如下:

    1. 前台进程(Foreground process)。它表明用户正在与该进程进行交互操作,android系统依据下面的条件来将一个进程标记为前台进程:

      • 该进程持有一个用户正在与其交互的Activity(也就是这个activity的生命周期方法走到了onResume()方法)。
      • 该进程持有一个Service,并且这个Service与一个用户正在交互中的Activity进行绑定。
      • 该进程持有一个前台运行模式的Service(也就是这个Service调用了startForegroud()方法)。
      • 该进程持有一个正在执行生命周期方法(onCreate()、onStart()、onDestroy()等)的Service。
      • 该进程持有一个正在执行onReceive()方法的BroadcastReceiver。

      一般情况下,不会有太多的前台进程。杀死前台进程是操作系统最后无可奈何的做法。当内存严重不足的时候,前台进程一样会被杀死。

    2. 可见进程(Visible process)。它表明虽然该进程没有持有任何前台组件,但是它还是能够影响到用户看得到的界面。android系统依据下面的条件将一个进程标记为可见进程:

      • 该进程持有一个非前台Activity,但这个Activity依然能被用户看到(也就是这个Activity调用了onPause()方法)。例如,当一个activity启动了一个对话框,这个activity就被对话框挡在后面。
      • 该进程持有一个与可见(或者前台)Activity绑定的Service。
    3. 服务进程(Service process)。除了符合前台进程和可见进程条件的Service,其它的Service都会被归类为服务进程。

    4. 后台进程(Background process)。持有不可见Activity(调用了onStop()方法)的进程即为后台进程。通常情况下都会有很多后台进程,当内存不足的时候,在所有的后台进程里面,会按照LRU(最近使用)规则,优先回收最长时间没有使用过的进程。

    5. 空进程(Empty process)。不持有任何活动组件的进程。保持这种进程只有一个目的,就是为了缓存,以便下一次启动该进程中的组件时能够更快响应。当资源紧张的时候,系统会平衡进程缓存和底层的内核缓存情况进行回收。

    如果一个进程同时满足上述5种优先级中的多个等级条件,android系统会优先选取其中最高的等级作为该进程的优先级。例如,一个进程持有一个Service(服务进程等级)和一个前台Activity(前台进程等级),那么操作系统会将这个进程标记为前台进程。

    另外需要注意的是,如果一个进程为另外一个进程提供服务,那么这个进程的优先级不会低于享受服务的进程。例如,假设进程A中的content provider为进程B提供服务,或者进程A中有一个Service与进程B中的组件进程绑定,那么进程A的优先级至少要与进程B一致,或者高于进程B。

    参考:https://developer.android.com/guide/components/processes-and-threads.html

    展开全文
  • linux 进程优先级设置

    千次阅读 2013-05-11 12:31:02
    注意:一下均是非实时进程优先级的设置 nice(1): 以指定优先级运行程序 nice [OPTION] [COMMAND [ARG]...] nice –n 1 ls renice(8): 调整运行进程优先级 renice priority [[-p] pid ....

    注意:一下均是非实时进程的优先级的设置


    nice(1): 以指定优先级运行程序

    nice [OPTION] [COMMAND [ARG]...]

    nice –n 1 ls

    renice(8): 调整运行进程的优先级

    renice priority [[-p] pid ...] [[-g] pgrp ...] [[-u] user ...]

    renice +1 987 -u daemon root -p 32

     

    API

    nice(2): 改变进程优先级

    int nice(int inc);

    getpriority(2): 获取优先级

    int getpriority(int which, int who);

    setpriority(2): 设置优先级

    int setpriority(int which, int who, int prio);


    展开全文
  • LINUX进程优先级实现

    千次阅读 2013-05-11 02:42:51
    进程调度的目标: 高效性:高效意味着在相同的时间下要完成更多的任务。调度程序会被频繁的执行,所以调度程序要尽可能的高效。加强交互性能(interactivity):在系统相当的负载下,也要保证系统的响应时间。...
  • 进程优先级

    千次阅读 2018-08-09 18:54:08
    1.进程优先级: 内核使用[0~139]这140个数来表示140种优先级。  内核使用一个简单些的数值范围,从0到139(包含),用来表示内部优先级。同样是值越低,优 先级越高。从0到99的范围专供实时进程使用。 nice值[20, +...
  • Android平台App进程优先级

    千次阅读 2016-08-29 11:02:56
    Android为了让App启动的时候能更快,会把那么暂时不使用的App的进程缓存起来,但是内存是有限的啊,总不能让所有的进程都放在内存里边吧,所以Android有一个淘汰机制,会根据App的运行状态设置一个进程优先级(oom...
  • 最近初学了Android系统的进程概念以及进程的排序,了解了进程在系统内部的工作流程以及原理。 下面是自己的理解和归纳... 可见进程部分程序界面是可见的,有可能被用户回调,优先级仅次于前台进程。 3.服务进程:...
  • 进程优先级调度算法

    2018-06-22 18:49:01
    《计算机与操作系统(第四版)》进程优先级调度算法 1.时间片轮转调度算法 2.多级反馈队列调度算法 3.高响应比优先调度算法
  • Android系统进程优先级排序原因

    千次阅读 2015-09-20 17:21:08
    最近初学了Android系统的进程概念以及进程的排序,了解了进程在系统内部的工作流程以及原理。... 可见进程部分程序界面是可见的,有可能被用户回调,优先级仅次于前台进程。 3.服务进程: 这里要注意一点
  • Android知识点之进程优先级

    千次阅读 2013-10-11 13:51:30
    取而代之的事,安卓的APP组件必须监听生命周期的改变,然后做出必要的回应,以免在一些特殊情况因为资源的紧张被系统杀死。 默认的,每个安卓程序都运行在一个独立的进程中,并且进程都运行在独立的Dalvik虚拟机...
  • 1.前台进程(Foreground process)。它表明用户正在与该进程进行交互操作,android系统依据下面的条件来将一个进程标记为前台进程: 该进程持有一个用户正在与其交互的Activity(也就是这个activity的生命周期...
  • 进程优先级实际上是系统对进程重要性的一个客观评价。根据这个评价的结果来为进程分配不同的系统资源,这个资源包括内存资源和CPU资源。为了保证“公平公正”的评价每个进程,Google工程师为此设计了一套评价系统。...
  • 进程优先级设置工具 进程优先级设置工具 命令行程序 ,打开程序可看到使用时的参数

空空如也

1 2 3 4 5 ... 20
收藏数 8,511
精华内容 3,404
关键字:

进程优先级