跳到主要内容

Linux 线程调度

1. 基本概念

Linux 线程调度是指系统核心为了提高系统的效率,分配处理器资源给每个线程并决定何时执行每个线程的过程。

Linux 线程调度优先级是指在进行线程调度时,线程调度器会考虑每个线程的优先级,并根据优先级分配处理器资源。一般来说,优先级越高的线程会获得更多的处理器时间,并且优先得到执行。可以通过操作系统提供的API来更改线程的优先级,通常情况下,优先级是一个整数值。

注意

如果在程序中设置了优先级,程序需要管理员运行。

2. 线程调度优先级

2.1 静态优先级

Linux 线程静态优先级指的是线程在创建时的优先级。

这个优先级一般由线程的创建者指定,并在线程创建时赋予线程。之后,线程的静态优先级将会一直保持不变,直到线程结束或者被删除。通常情况下,在创建线程时,如果没有指定线程的静态优先级,线程将会被赋予一个中间值的默认优先级。

静态优先级的范围为(0~99),数字越大优先级越高。

  • 1-99为实时线程,有两种系统调度方式。
    • FIFO(先进先出):任务同优先级情况下,会一直占着CPU运行,直到任务完成才会进行下一个。
    • RR(时间片轮转):任务同优先级情况下,会给每个任务分配时间片,时间耗尽就会切换到另一个同优先级的任务。
  • 0为非实时(普通)线程:OTHER(其他)。

2.2 动态优先级

Linux线程动态优先级是指线程在运行时的优先级。

这个优先级可能会根据线程的运行情况发生变化。通常情况下,线程调度器会根据线程的运行情况来调整线程的动态优先级。例如,如果一个线程消耗了大量的处理器时间,那么线程调度器可能会降低这个线程的动态优先级,以便给其它线程分配更多的处理器资源。

动态优先级的范围为(-20~19),数字越小,优先级越高。

动态优先级只对非实时线程有效(静态优先级为0)。

  • CPU消耗性降低:高清视频解码。
  • I/O消耗性提高:编辑器。

3. 线程调度API

3.1 设置调度参数

pthread_attr_setschedparam( ) 是Linux线程库中的一个函数,用于设置线程属性对象中线程的调度参数。该函数原型为:

int pthread_attr_setschedparam(pthread_attr_t *attr,const struct sched_param *param);	

该函数需要两个参数:

  • attr:指向线程属性对象的指针。
  • param:指向调度参数结构体的指针。调度参数结构体包含了线程的优先级,以及其它一些调度相关的信息。

该函数通过更新线程属性对象中的信息来设置线程的调度参数。

该函数返回一个整数值,如果返回0,则表示设置成功;如果返回其它值,则表示设置失败。

3.2 设置调度策略

pthread_attr_setschedpolicy( ) 是Linux线程库中的一个函数,用于设置线程属性对象中线程的调度策略。该函数原型为

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);

函数数需要两个参数:

  • attr:指向线程属性对象的指针。
  • policy:指定线程的调度策略。可以是SCHED_FIFO、SCHED_RR或SCHED_OTHER之一。

该函数通过更新线程属性对象中的信息来设置线程的调度策略。 该函数返回一个整数值,如果返回0,则表示设置成功;如果返回其它值,则表示设置失败。

3.3 设置继承策略

pthread_attr_setinheritsched( ) 是Linux线程库中的一个函数,用于设置线程属性对象中线程的继承调度属性。该函数原型为:

int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);	

该函数需要两个参数:

  • attr:指向线程属性对象的指针。
  • inheritsched:指定线程是否继承父线程的调度属性。可以是PTHREAD_INHERIT_SCHED或PTHREAD_EXPLICIT_SCHED之一。

如果指定为HREAD_INHERIT_SCHED,则线程将继承其父线程的调度属性;如果指定为PTHREAD_EXPLICIT_SCHED,则线程的调度属性将由线程属性对象中的信息决定。

该函数通过更新线程属性对象中的信息来设置线程的继承调度属性。

该函数返回一个整数值,如果返回0,则表示设置成功;如果返回其它值,则表示设置失败。

4. 示例代码

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

void *thread_func(void *arg)
{
#ifdef OTHER
if('A' == *(char *)arg) {
nice(1); //A线程的nice值
} else {
nice(-10); //B线程的nice值
}
#endif

while(1) {
fprintf(stderr, "%c", *(char *)arg);
// usleep(10); //会导致任务进入睡眠态
}
}

int main(int argc, char *argv[])
{
// 定义两个线程号变量
pthread_t t1, t2;

// 定义两个线程属性变量
pthread_attr_t attr1, attr2;

// 初始化线程属性变量
pthread_attr_init(&attr1);
pthread_attr_init(&attr2);

// 设置使用属性变量中的策略
pthread_attr_setinheritsched(&attr1, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setinheritsched(&attr2, PTHREAD_EXPLICIT_SCHED);

// 设定静态优先级
struct sched_param parm1 = {0};
struct sched_param parm2 = {0};

// 设置调度策略
#ifdef FIFO
pthread_attr_setschedpolicy(&attr1, SCHED_FIFO);
pthread_attr_setschedpolicy(&attr2, SCHED_FIFO);
#endif

#ifdef RR
pthread_attr_setschedpolicy(&attr1, SCHED_RR);
pthread_attr_setschedpolicy(&attr2, SCHED_RR);
#endif

#ifdef OTHER
pthread_attr_setschedpolicy(&attr1, SCHED_OTHER);
pthread_attr_setschedpolicy(&attr2, SCHED_OTHER);
#endif

// 设置静态优先级
pthread_attr_setschedparam(&attr1, &parm1);
pthread_attr_setschedparam(&attr2, &parm2);

// 创建线程
pthread_create(&t1, &attr1, thread_func, "A");
pthread_create(&t2, &attr2, thread_func, "B");

// 阻塞, 等待信号
pause();

return 0;
}