【Linux】实时线程的优先级设置、调度和抢占

前言

看了一些关于Linux多线程编程的书籍和网络资料,发现关于对实时线程调度和抢占的主题的代码和文章比较少(也可能是我还没找到)。而对于一些系统,例如机器人控制系统,对于任务的实时性要求是比较高的,所以需要了解一下实时线程的编程方法。
Linux虽然是一个非实时操作系统,但是其线程也有实时和分时之分,具体的调度策略可以分为3种:
实时线程:SCHED_FIFO(先来先服务策略调度);
实时线程:SCHED_RR(时间片轮转);
普通线程:Linux中称为SCHED_MORMAL;POSIX称为SCHED_OTHER,是一种分时调度策略。
我们创建线程的时候可以指定调度策略,默认的调度策略为SCHED_OTHER。

示例代码

下边给出一个Linux实时线程抢占的编程示例,我认为尤其需要注意的两点是:
(1)必须在sudo模式下运行程序;
(2)需要将实时线程绑定到同一个CPU核上;

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

#define __USE_GNU

long long a = 0;
long long b = 0;

// 获取调度策略的函数
static int get_thread_policy(pthread_attr_t *attr)
{
    int policy;
    int rs = pthread_attr_getschedpolicy(attr, &policy);
    // assert(rs == 0);
    switch (policy)
    {
    case SCHED_FIFO:
        printf("policy= SCHED_FIFO\n");
        break;
    case SCHED_RR:
        printf("policy= SCHED_RR");
        break;
    case SCHED_OTHER:
        printf("policy=SCHED_OTHER\n");
        break;
    default:
        printf("policy=UNKNOWN\n");
        break;
    }
    return policy;
}

// 将线程绑定到某个cpu核上
int attach_cpu(int cpu_index)
{
    int cpu_num = sysconf(_SC_NPROCESSORS_CONF);
    if (cpu_index < 0 || cpu_index >= cpu_num)
    {
        printf("cpu index ERROR!\n");
        return -1;
    }
    
    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(cpu_index, &mask);

    if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0)
    {
        printf("set affinity np ERROR!\n");
        return -1;
    }

    return 0;
}

// 线程函数1
void *thread1(void *param)
{
    attach_cpu(0);

    long long i;
    for (i = 0; i < 10000000000; i++)
    {
        a++;
    }
}

// 线程函数2
void *thread2(void *param)
{
    attach_cpu(0);

    long long i;
    for (i = 0; i < 10000000000; i++)
    {
        b++;
    }
}

int main()
{
    pthread_t t1;
    pthread_t t2;
    pthread_attr_t attr1;
    pthread_attr_t attr2;
    struct sched_param param1;
    struct sched_param param2;

    //1、初始化
    pthread_attr_init(&attr1);
    pthread_attr_init(&attr2);

    //2、自己决定调度策略
    pthread_attr_setinheritsched(&attr1, PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setinheritsched(&attr2, PTHREAD_EXPLICIT_SCHED);

    //3、设置调度策略
    pthread_attr_setschedpolicy(&attr1, SCHED_FIFO);
    pthread_attr_setschedpolicy(&attr2, SCHED_FIFO);
    // 获取调度策略
    get_thread_policy(&attr1);
    get_thread_policy(&attr2);

    //4、设置优先级
    param1.sched_priority = 10;// 线程1设置优先级为10
    param2.sched_priority = 12;// 线程2设置优先级为12
    pthread_attr_setschedparam(&attr1, &param1);
    pthread_attr_setschedparam(&attr2, &param2);

    //5、创建线程
    pthread_create(&t1, &attr1, thread1, NULL);
    sleep(1);
    pthread_create(&t2, &attr2, thread2, NULL);

    while (1)
    {
        printf("a=%lld, b=%lld\n", a, b);
        sleep(1);
    }

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    return 0;
}

代码结果

这里线程2的优先级设置为12,大于线程1的优先级11,所以线程2一旦就绪,就会抢占CPU资源,进入运行态,而线程1进入就绪态。如下所示,线程函数1中的a累加到366407710后就不再累加,被线程函数2中的b累加抢占,持续运行下去。

[linux-xx@xxx]$ sudo ./test 
policy= SCHED_FIFO
policy= SCHED_FIFO
a=366407710, b=0
a=366407710, b=360397117
a=366407710, b=720418977
a=366407710, b=1080623671
a=366407710, b=1443246909
a=366407710, b=1802815022
a=366407710, b=2165877123
^C
posted @   gpeng832  阅读(320)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示