• 线程绑定CPU、线程优先级的设置


    刚开始的代码是这样的:

    #include
    #include
    #include
    #include
    
    void* thread(void *arg) {
        char ch = *(char *)arg;
        while(1) {
            printf("%c",ch);
            fflush(stdout);
            //sleep(1);
        }
    }
    
    int main(int argc, char *argv[]) {
        pthread_t t1, t2;
        char ch1 = 'A', ch2 = 'B';
    
        pthread_create(&t1, NULL, thread, (void*)&ch1);
        pthread_create(&t2, NULL, thread, (void*)&ch2);
    
        pthread_join(t1, NULL);
        pthread_join(t2, NULL);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    此时输出A 和B都是随机的,我现在想要只输出A而不输出B,也就是需要改变线程的优先级。

    下面的代码设置两个线程的优先级为100 和 200,按道理来说应该只会输出优先级高的线程,结果却和前面一样,两个都会输出。

    #include
    #include
    #include
    #include
    
    void* thread(void *arg) {
        char ch = *(char *)arg;
        while(1) {
            printf("%c",ch);
            fflush(stdout);
            //sleep(1);
        }
    }
    
    int main(int argc, char *argv[]) {
        pthread_t t1, t2;
        pthread_attr_t attr;
        struct sched_param sch;
        char ch1 = 'A', ch2 = 'B';
    
        pthread_attr_init(&attr);
        pthread_attr_getschedparam(&attr, &sch);
        sch.sched_priority = 100;
        pthread_attr_setschedparam(&attr, &sch);
    
        pthread_create(&t1, &attr, thread, (void*)&ch1);
        sch.sched_priority = 200;
        pthread_attr_setschedparam(&attr, &sch);
        pthread_create(&t2, &attr, thread, (void*)&ch2);
    
        pthread_join(t1, NULL);
        pthread_join(t2, NULL);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    上网查发现是linux调度策略的问题,linux有多种调度策略,在某些调度策略下线程优先级高只是代表它有更大的几率获得CPU资源,并不是说优先级高的就一定比优先级低的先获得CPU,网上搜到的调度策略如下:

    1.SCHED_OTHER 分时调度策略

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

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

    由上面可知要实现我的需求应该设置调度策略为 SCHED_FIFO,可是怎么设置呢?继续百度,发现用户空间程序可以使用sched_setscheduler()来设定用户进程的调度策略。

    通过man手册查看函数的用法。发现这是设置进程的,而不是线程。

    pthread_attr_setschedpolicy是设置线程调度策略的函数,使用了这个函数之后发现还是不行,再问,发现需要先设置线程的调度属性,因为默认情况下线程的调度属性是继承的,此时设置是无效的,我们必须先通过pthread_attr_setinheritsched设置PTHREAD_EXPLICIT_SCHED(默认是PTHREAD_INHERIT_SCHED)后pthread_attr_setschedpolicy设置调度策略才是有效的。

    可问题是即使我按照如上操作进行,最后的结果也不是我想要的,最后在网上一篇博客的帮助下才解决,

    (3条消息) 【Linux】实时线程的优先级设置、调度和抢占_gpeng832的博客-CSDN博客

    原来是要显式的指定每个线程要绑定在哪个CPU上,最终代码如下:

    需要注意的点有:

    1. #define _GNU_SOURCE这个宏的定义最好是放在开头,我之前就是因为这个宏放在某个头文件后面导致没有用,以后要养成把这类宏放在开头的好习惯
    2. 程序运行的时候需要root权限
    #define _GNU_SOURCE
    #include
    #include
    #include
    #include
    #include
    
    int attach_cpu(int cpu_index);
    void* thread(void *arg);
    static int get_thread_policy(pthread_attr_t *attr);
    
    int main(int argc, char *argv[]) {
    
        pthread_t t1, t2;
        char ch1 = 'A', ch2 = 'B';
        
        pthread_attr_t attr1, attr2;
        pthread_attr_init(&attr1);
        pthread_attr_init(&attr2);
    
        struct sched_param sch1, sch2;
        sch1.sched_priority = 8;
        sch2.sched_priority = 10;
        
        pthread_attr_setinheritsched(&attr1, PTHREAD_EXPLICIT_SCHED);
        pthread_attr_setinheritsched(&attr2, PTHREAD_EXPLICIT_SCHED);
        
        pthread_attr_setschedpolicy(&attr1, SCHED_FIFO);
        pthread_attr_setschedpolicy(&attr2, SCHED_FIFO);
        
        pthread_attr_setschedparam(&attr1, &sch1);
        pthread_attr_setschedparam(&attr2, &sch2);
    
        pthread_create(&t1, &attr1, thread, (void*)&ch1);
        pthread_create(&t2, &attr2, thread, (void*)&ch2);
    
        pthread_join(t1, NULL);
        pthread_join(t2, NULL);
    
        return 0;
    }
    
    void* thread(void *arg) {
    
        attach_cpu(0);
    
        char ch = *(char *)arg;
        
        while(1) {
            printf("%c",ch);
            fflush(stdout);
            //sleep(1);
        }
    }
    
    // 获取调度策略的函数
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101

    attach_cpu函数中用到了许多没见过的函数。

    sysconf(_SC_NPROCESSORS_CONF)是获取可用的CPU核数。

    为了跨平台的需要,我们需要同时考虑在不同平台下获取机器处理器核数的方法。在这里我们考虑Linux与Windows两个平台,不同的平台有不同的方法来获取处理器核数。

    在Windows平台下,我们可以使用GetSystemInfo( )这个函数来获取当前系统的一些软硬件信息。其中有一项即是当前机器中处理器的核数。通过如下语句即可获得所要的信息:
    SYSTEM_INFO info;
    GetSystemInfo(&info);
    return info.dwNumberOfProcessors;

    而在Linux平台下,我们可以使用sysconf( )或者get_nprocs( )来获取处理器核数。下面分别介绍:
    sysconf( )有unistd.h提供,要使用该函数需要#include,其参数可以是_SC_NPROCESSORS_CONF,也可以是_SC_NPROCESSORS_ONLN。sysconf(_SC_NPROCESSORS_CONF)返回系统可以使用的核数,但是其值会包括系统中禁用的核的数目,因此该值并不代表当前系统中可用的核数。而sysconf(_SC_NPROCESSORS_ONLN)的返回值真正的代表了系统当前可用的核数。

    GNU C库提供了另外一种获取机器可用核数的方法。函数int
    get_nprocs_conf (void),int get_nprocs (void)在 sys/sysinfo.h中定义,这两个函数可用获取机器的核数。其中get_nprocs_conf (void)的返回值与sysconf(_SC_NPROCESSORS_CONF)类似,并不真正表名当前可用核数;而get_nprocs
    (void)的返回值与sysconf(_SC_NPROCESSORS_ONLN)类似,真正的反映了当前可用核数。

    cpu_set_t mask; 创建一个CPU集合

    CPU_ZERO(&mask);将该集合清零

    CPU_SET(cpu_index, &mask); 添加第cpu_index个内核到maskCPU集合中

    pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask)这个函数可能是设置第一个参数中的线程只使用CPU集合mask中的CPU,第二个参数是CPU集合中CPU的个数。

  • 相关阅读:
    web表格(详解)
    YB5302是一款工作于2.7V到6.5V的PFM升压型双节锂电池充电控制集成电路
    并发编程- 线程池ForkJoinPool工作原理分析(实践)
    Linux免交互
    Java类和对象(一)
    景联文科技带你了解数据标注之文本标注
    第七章 总结及作业【编译原理】
    LeetCode:1465. 切割后面积最大的蛋糕(C++)
    C++:用函数模板排列数组
    《编写高质量代码-改善C程序代码的125个建议》读书笔记-2 表达式 、控制语句
  • 原文地址:https://blog.csdn.net/m0_45972156/article/details/126889435