上官银柳 发表于 2025-6-11 15:52:13

Linux线程的调度策略

Linux线程的调度策略

Linux系统中所有的程序得到运行都会变为一个进程(process),而进程中可能会存在一个或者多个任务(task),这些任务就以进程中的线程(thread)作为载体,所以线程就是系统调度的最小单位。
线程的调度策略

A. SCHED_OTHER
SCHED_OTHER调度策略指的是分时调度策略,是Linux系统中默认的调度策略,一般采用CFS(Completely Fair Scheduler)算法,该算法为运行队列中的每一个进程都设置一个虚拟时钟vruntime(Virtual Runtime)
如果一个进程得到执行,随着执行时间的不断增长,其vruntime也将不断增大,没有得到执行的进程vruntime将保持不变。而调度器将会选择最小的vruntime那个进程来执行。这就是所谓的“完全公平”。不同优先级的进程其vruntime增长速度不同,优先级高的进程vruntime增长得慢,所以可能会得到更多的运行机会。
注意:如果一个线程以SCHED_OTHER调度策略进行创建,线程的静态优先级必须设置为0。
B. SCHED_FIFO
SCHED_FIFO调度策略指的是实时调度策略,采用“*先到先服务*”的调度方式,当一条线程采用该调度策略则会一直运行,直到它被更高优先级的线程抢占或者主动放弃CPU,才会交出控制权。
当线完成后,内核会去寻找处于就绪状态相同优先级的线程,如果不存在,则寻找低优先级线程。该调度策略实现了数据的互斥,在线程运行的时间内其他相同优先级线程无法进行资源抢占。
C. SCHED_RR
SCHED_RR(Round Robin,中文意为轮询)指的是实时调度策略,是一种基于*时间片轮转*的调度策略,它会给每个线程设置一个固定的优先级,并按照优先级顺序对线程进行轮流调度。
当一条线程采用该调度策略则会一直运行,直到它被更高优先级的线程抢占、主动放弃CPU以及消耗完自己的时间片,才会交出控制权。
时间片是线程运行的最小时间单元,由操作系统预先设定。当时间片用完时,该线程自动交出控制权,之后内核会按照和FIFO相同的方式搜索下一个工作线程。
轮转调度可以防止某一个任务连续占用太多的资源,而导致其他线程信息得不到及时处理。缺点是轮转调度会增大由于任务切换(任务上下文)而导致的开销。
优先级别

Linux系统中任务优先级分为两种:一种是静态优先级,一种是动态优先级,两者区别如下:
(1)静态优先级
静态优先级指的是任务一旦设置好优先级之后就不能再改变,相当于是任务本身的属性,通过Linux系统内核源码中的头文件sched.h可以知道,线程的优先级范围是0~99,优先级数值越大则优先级越高。
Linux系统中普通任务的优先级是0,系统任务的优先级是1~99,也就是说普通任务可能随时会被系统任务抢占。普通任务的静态优先级必须被设定为0,意味着普通任务无法跟系统任务参与系统资源的竞争,普通任务彼此之间的用动态优先级去竞争系统资源。
Linux系统中提供了两个函数接口来设置以及获取线程的继承调度属性,分别是pthread_attr_setinheritsched()和pthread_attr_getinheritsched()
int pthread_attr_setinheritsched(pthread_attr_t *attr,int inheritsched);//设置线程的继承属性
int pthread_attr_getinheritsched(const pthread_attr_t *attr,int *inheritsched);//查看线程的继承属性第一个参数:attr指的是线程的属性对象,用户在创建线程之前可以先设置线程的属性,其中线程的属性就包含线程的调度属性,线程的属性对象attr在调用pthread_attr_init()函数初始化之后,*默认是继承*创建该线程的线程的调度属性。
第二个参数:inheritsched指的是线程的属性是打算继承创建该线程的线程的调度属性或者指定为线程属性对象attr中的调度属性,如果该参数为PTHREAD_EXPLICIT_SCHED,则表示线程的调度属性指定为attr的值。
注意:一条线程如果以默认的属性进行创建,则该线程的调度策略被设置为SCHED_OTHER,并且线程的优先级默认设置为0,也就意味着创建的线程属于普通任务。
Linux系统中线程创建时如果采用默认的属性,则线程的调度策略就是SCHED_OTHER,当然,Linux系统提供了一个名称叫做pthread_attr_setschedpolicy()的函数,用户可以利用该函数设置线程的调度属性。
练习:创建一条指定属性的线程,要求线程的调度策略为先到先服务策略,提示:创建属性对象 --> 初始化属性对象 --> 设置属性对象的继承调度属性(不继承) --> 设置调度策略!
#include <stdio.h>
#include <pthread.h>

void * task(void * arg)
{

}

int main()
{
    //1.初始化线程的属性
    pthread_attr_t attr;
    pthread_attr_init(&attr);

    //2.初始化之后设置线程的继承属性
    int inheritsched;
    pthread_attr_getinheritsched(&attr,&inheritsched);

    //3.表达式成立,说明默认线程属性对象中默认是:继承
    if(inheritsched=PTHREAD_INHERIT_SCHED)
    {
      printf("INHERIT\n");
    }
    else
    {
      printf("EXPLICIT\n");
    }

    //4.设置线程的属性,不继承

    pthread_attr_setinheritsched(&attr,PTHREAD_EXPLICIT_SCHED);

    //5.修改线程的调度策略为先来先服务

    pthread_attr_setschedpolicy(&attr,SCHED_FIFO);

    //6.创建线程

    pthread_t thread;
    pthread_create(&thread,&attr,task,NULL);
   
    while(1)
    {

    }
    return 0;
}思考:用户设置好线程的调度策略后,如果准备对不同优先级的线程进行调度,请问如何来设置线程的静态优先级?
回答:Linux系统提供了一个名称叫做pthread_attr_setschedparam()的函数,用户利用该函数可以设置线程的优先级
练习:编写一个多线程程序,要求采用SCHED_FIFO调度策略创建两条相同静态优先级的线程,一个线程的任务是在死循环输出数字09,另一个线程的任务是在死循环输出字母az,观察其运行效果。提示:需要确保Linux系统的处理器数量和内核数量为1。
#include #include pthread_attr_t attr;//子线程1调度策略:FIFO 优先级:1void *task1(void *arg){        //循环输出0~9        while(1)        {      int i=0;                if(i
页: [1]
查看完整版本: Linux线程的调度策略