• 多线程cpu affinity问题


    为了提高多线程程序的性能,有时候需要将线程绑定到固定的cpu core上。

    在这个过程中一不小心就会产生编译的问题,但是明明头文件都定义了,却依然编译通不过。

    不巧我就遇到了,google也基本搜不到这个问题的解决方案,没办法,只能自己解决了。

    下面这个程序就会出现这种问题:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. #include <stdio.h>  
    2. #include <pthread.h>  
    3. #define __USE_GNU  
    4. #include <sched.h>  
    5.   
    6. void mybind_cpu(int cpu_id)  
    7. {  
    8.     cpu_set_t mask;  
    9.     //! sched_setaffinity  
    10.     CPU_ZERO(&mask);  
    11.     CPU_SET(cpu_id, &mask);  
    12.     if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) < 0) {  
    13.         printf("Error: cpu id %d sched_setaffinity ", cpu_id);  
    14.         printf("Warning: performance may be impacted  ");  
    15.     }  
    16.     return;  
    17. }  
    18.   
    19. void test_thread(void *cpu_id)  
    20. {  
    21.     int cpuid = (int)(long)cpu_id;    
    22.     mybind_cpu(cpuid);  
    23.     printf("test success! ");  
    24.     return;  
    25. }  
    26.   
    27. int main(int argc, char **argv)  
    28. {  
    29.     int res;  
    30.     void *thread_result;  
    31.     pthread_t test_thread_ctrl;  
    32.     pthread_create(&test_thread_ctrl, NULL, (void *)test_thread, (void *)0);  
    33.     res = pthread_join(test_thread_ctrl, &thread_result);  
    34.     (void)res;  
    35.     return 0;  
    36. }  


    运行编译命令,编译无法通过:

    gcc  test.c -g -Wall -lpthread -o test 
    test.c: In function ‘mybind_cpu’:
    test.c:10:5: warning: implicit declaration of function ‘CPU_ZERO’ [-Wimplicit-function-declaration]
         CPU_ZERO(&mask);
         ^
    test.c:11:5: warning: implicit declaration of function ‘CPU_SET’ [-Wimplicit-function-declaration]
         CPU_SET(cpu_id, &mask);
         ^
    test.c:12:5: warning: implicit declaration of function ‘sched_setaffinity’ [-Wimplicit-function-declaration]
         if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) < 0) {
         ^
    /tmp/cc0z5zPj.o: In function `mybind_cpu':
    /home/youfu/test.c:10: undefined reference to `CPU_ZERO'
    /home/youfu/test.c:11: undefined reference to `CPU_SET'
    collect2: error: ld returned 1 exit status

    可以看到提示一些变量没有定义, 但是我们明明include了头文件<sched.h>,而且前面添加了#define __USE_GNU,莫非这些宏定义是在别的头文件中吗?

    我们打开/usr/include/sched.h文件, 发现只要#define __USE_GNU,那么就会定义相关的宏,sched.h文件相关定义的源码如下:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. #ifdef __USE_GNU  
    2. /* Access macros for `cpu_set'.  */  
    3. # define CPU_SETSIZE __CPU_SETSIZE  
    4. # define CPU_SET(cpu, cpusetp)   __CPU_SET_S (cpu, sizeof (cpu_set_t), cpusetp)  
    5. # define CPU_CLR(cpu, cpusetp)   __CPU_CLR_S (cpu, sizeof (cpu_set_t), cpusetp)  
    6. # define CPU_ISSET(cpu, cpusetp) __CPU_ISSET_S (cpu, sizeof (cpu_set_t),   
    7.                         cpusetp)  
    8. # define CPU_ZERO(cpusetp)   __CPU_ZERO_S (sizeof (cpu_set_t), cpusetp)  
    9. # define CPU_COUNT(cpusetp)  __CPU_COUNT_S (sizeof (cpu_set_t), cpusetp)  
    10.   
    11. # define CPU_SET_S(cpu, setsize, cpusetp)   __CPU_SET_S (cpu, setsize, cpusetp)  
    12. # define CPU_CLR_S(cpu, setsize, cpusetp)   __CPU_CLR_S (cpu, setsize, cpusetp)  
    13. # define CPU_ISSET_S(cpu, setsize, cpusetp) __CPU_ISSET_S (cpu, setsize,   
    14.                                cpusetp)  
    15. # define CPU_ZERO_S(setsize, cpusetp)       __CPU_ZERO_S (setsize, cpusetp)  
    16. # define CPU_COUNT_S(setsize, cpusetp)      __CPU_COUNT_S (setsize, cpusetp)  
    17.   
    18. # define CPU_EQUAL(cpusetp1, cpusetp2)   
    19.   __CPU_EQUAL_S (sizeof (cpu_set_t), cpusetp1, cpusetp2)  
    20. # define CPU_EQUAL_S(setsize, cpusetp1, cpusetp2)   
    21.   __CPU_EQUAL_S (setsize, cpusetp1, cpusetp2)  
    22.   
    23. # define CPU_AND(destset, srcset1, srcset2)   
    24.   __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, &)  
    25. # define CPU_OR(destset, srcset1, srcset2)   
    26.   __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, |)  
    27. # define CPU_XOR(destset, srcset1, srcset2)   
    28.   __CPU_OP_S (sizeof (cpu_set_t), destset, srcset1, srcset2, ^)  
    29. # define CPU_AND_S(setsize, destset, srcset1, srcset2)   
    30.   __CPU_OP_S (setsize, destset, srcset1, srcset2, &)  
    31. # define CPU_OR_S(setsize, destset, srcset1, srcset2)   
    32.   __CPU_OP_S (setsize, destset, srcset1, srcset2, |)  
    33. # define CPU_XOR_S(setsize, destset, srcset1, srcset2)   
    34.   __CPU_OP_S (setsize, destset, srcset1, srcset2, ^)  
    35.   
    36. # define CPU_ALLOC_SIZE(count) __CPU_ALLOC_SIZE (count)  
    37. # define CPU_ALLOC(count) __CPU_ALLOC (count)  
    38. # define CPU_FREE(cpuset) __CPU_FREE (cpuset)  
    39.   
    40.   
    41. /* Set the CPU affinity for a task */  
    42. extern int sched_setaffinity (__pid_t __pid, size_t __cpusetsize,  
    43.                   const cpu_set_t *__cpuset) __THROW;  
    44.   
    45. /* Get the CPU affinity for a task */  
    46. extern int sched_getaffinity (__pid_t __pid, size_t __cpusetsize,  
    47.                   cpu_set_t *__cpuset) __THROW;  
    48. #endif  


    好的,没办法,通过gcc的预编译选项来查看到底预编译的代码是什么, 在预处理生成的文件中有没有相关定义,运行下面命令生成预处理文件test.i

    gcc -E test.c -g -Wall -lpthread -o test.i

    预编译生成的文件非常大,大概有2000多行,找到其中sched.h相关的部分,发现预处理没有把#define __USE_GNU相关的宏定义包含进来:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. extern int sched_setparam (__pid_t __pid, const struct sched_param *__param)  
    2.      __attribute__ ((__nothrow__ , __leaf__));  
    3.   
    4.   
    5. extern int sched_getparam (__pid_t __pid, struct sched_param *__param) __attribute__ ((__nothrow__ , __leaf__));  
    6.   
    7.   
    8. extern int sched_setscheduler (__pid_t __pid, int __policy,  
    9.           const struct sched_param *__param) __attribute__ ((__nothrow__ , __leaf__));  
    10.   
    11.   
    12. extern int sched_getscheduler (__pid_t __pid) __attribute__ ((__nothrow__ , __leaf__));  
    13.   
    14.   
    15. extern int sched_yield (void) __attribute__ ((__nothrow__ , __leaf__));  
    16.   
    17.   
    18. extern int sched_get_priority_max (int __algorithm) __attribute__ ((__nothrow__ , __leaf__));  
    19.   
    20.   
    21. extern int sched_get_priority_min (int __algorithm) __attribute__ ((__nothrow__ , __leaf__));  
    22.   
    23.   
    24. extern int sched_rr_get_interval (__pid_t __pid, struct timespec *__t) __attribute__ ((__nothrow__ , __leaf__));  
    25. # 125 "/usr/include/sched.h" 3 4  


    第一感觉这个肯定不是gcc的bug, 这就说明__USE_GNU这个宏定义不知到为什么没有起作用。

    只能是pthread.h在作怪,打开/usr/include/pthread.h, 重大发现:

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. #include <features.h>  
    2. #include <endian.h>  
    3. #include <sched.h>  
    4. #include <time.h>  
    5.   
    6. #include <bits/pthreadtypes.h>  
    7. #include <bits/setjmp.h>  
    8. #include <bits/wordsize.h>  


    在pthread.h中也include 了<sched.h>,但是没有定义__USE_GNU,所以后面的include <sched.h>就没有作用了。

    其实从预编译生成的文件就可以看出来, pthread相关的定义是在最后,但是明显我们是pthread.h是在sched.h前面的,这个也可以说明我们自己的c文件中的sched.h没有被包含进来,而是包含别的头文件中的sched.h

    解决方案就很简单了,将pthread.h的定义放到sched.h的后面就可以了。

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. #include <stdio.h>  
    2. #define __USE_GNU  
    3. #include <sched.h>  
    4. #include <pthread.h>  



    gcc  test.c -g -Wall -lpthread -o test 
     ./test 

    test success!

    打完收工!

  • 相关阅读:
    取得GridView被隐藏列的值方法集合
    【转】ASP.NET 数据分页第一篇 探讨分页原理及 SQL Server 2005 的 ROW_NUMBER 函数
    浏览器的工作原理:新式网络浏览器幕后揭秘
    无法装载文件或者汇编的AjaxControlToolkit
    【转】ASP.NET 数据分页第二篇 范例下载
    在用户控件中FindControl控件
    【转】ASP.NET 数据分页第三篇 结合 Custom Control 处理 GridView 的 UI 呈现
    Ajax Toolkit AutoComplete 几种用法
    到底如何区分什么是架构、框架、模式和平台 ?
    因果推理综述——《A Survey on Causal Inference》一文的总结和梳理
  • 原文地址:https://www.cnblogs.com/ghostll/p/3587194.html
Copyright © 2020-2023  润新知