【问题标题】:how to set CPU affinity of a particular pthread?如何设置特定 pthread 的 CPU 亲和性?
【发布时间】:2010-11-27 07:48:36
【问题描述】:

我想指定特定 pthread 的 cpu-affinity。到目前为止,我发现的所有参考资料都涉及设置进程 (pid_t) 而不是线程 (pthread_t) 的 cpu 亲和性。我尝试了一些通过 pthread_t 的实验,但正如预期的那样,它们失败了。我在尝试做一些不可能的事情吗?如果没有,您可以发送一个指针吗?谢谢一百万。

【问题讨论】:

    标签: multithreading cpu processor affinity


    【解决方案1】:

    这是我为让我的生活更轻松而制作的包装。其效果是调用线程“卡”在 id core_id 的核心上:

    // core_id = 0, 1, ... n-1, where n is the system's number of cores
    
    int stick_this_thread_to_core(int core_id) {
       int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
       if (core_id < 0 || core_id >= num_cores)
          return EINVAL;
    
       cpu_set_t cpuset;
       CPU_ZERO(&cpuset);
       CPU_SET(core_id, &cpuset);
    
       pthread_t current_thread = pthread_self();    
       return pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset);
    }
    

    【讨论】:

    • 供将来参考:需要添加#define _GNU_SOURCE 和#include 才能在gcc 4.7.2 上工作。在 arch linux 上完美运行,使用 oprofile 和 pthread 测试。
    • 另外,sysconfgcc 4.8.1 需要 #include &lt;unistd.h&gt;
    • 由于某种原因,它可以在我的具有两个内核的计算机上运行,​​但是在我的另一台具有 4 个内核的计算机上,它会给出以下错误:
      Segmentation fault (core dumped)
    • 不错。当 core_id > num_cores 时,另一个参数可以指定默认值,而不是失败:core_id = default_core; -1 作为默认值可能意味着失败。
    • 使用此代码或sched_setaffinity 来自下面的@nos 答案更好?
    【解决方案2】:

    假设是 linux:

    设置亲和力的界面是——你可能已经发现了:

    int sched_setaffinity(pid_t pid,size_t cpusetsize,cpu_set_t *mask);
    

    将 0 作为 pid 传递,它将仅适用于当前线程,或者让其他线程通过特定于 linux 的调用 pid_t gettid(void); 报告其内核 pid,并将其作为 pid 传递。

    引用man page

    亲和掩码实际上是每个线程的属性,可以 独立调整每个 线程组中的线程。价值 从 gettid(2) 调用返回的可以 在参数 pid 中传递。 将 pid 指定为 0 将设置 调用线程的属性,以及 传递调用返回的值 to getpid(2) 将设置属性 对于线程的主线程 团体。 (如果您使用的是 POSIX 线程 API,然后使用 pthread_setaffinity_np (3) 而不是 sched_setaffinity().)

    【讨论】:

    • “如果您使用 POSIX 线程 API,则使用 pthread_setaffinity_np (3) 而不是 sched_setaffinity()”。我应该如何知道我是否在使用 POSIX API?如何选择使用sched_setaffinitypthread_setaffinity_np
    • 在 RHEL 7 中这是人所说的 If pid is zero, then the calling process is used.(进程,而不是线程)
    • @javapowered 手册页中的那句话是错误的。也请阅读注释部分。
    • 我也有同样的问题,但是我用的是OS X,有没有类似的方法?
    • @Raghav OS X 没有公开将线程固定到特定内核的功能。
    【解决方案3】:
    //compilation: gcc -o affinity affinity.c -lpthread
    
    #define _GNU_SOURCE
    #include <sched.h>   //cpu_set_t , CPU_SET
    #include <pthread.h> //pthread_t
    #include <stdio.h>
    
    void *th_func(void * arg); 
    
    int main(void) {
      pthread_t thread; //the thread
    
      pthread_create(&thread,NULL,th_func,NULL); 
    
      pthread_join(thread,NULL);   
    
      return 0;
    }
    
    
    void *th_func(void * arg)
    {  
      //we can set one or more bits here, each one representing a single CPU
      cpu_set_t cpuset; 
    
      //the CPU we whant to use
      int cpu = 2;
    
      CPU_ZERO(&cpuset);       //clears the cpuset
      CPU_SET( cpu , &cpuset); //set CPU 2 on cpuset
    
    
      /*
       * cpu affinity for the calling thread 
       * first parameter is the pid, 0 = calling thread
       * second parameter is the size of your cpuset
       * third param is the cpuset in which your thread will be
       * placed. Each bit represents a CPU
       */
      sched_setaffinity(0, sizeof(cpuset), &cpuset);
    
      while (1);
           ; //burns the CPU 2
    
      return 0;
    }
    

    在 POSIX 环境中,您可以使用 cpusets 来控制 进程或 pthread 可以使用哪些 CPU。 这种类型的控制称为 CPU 亲和性。

    函数“sched_setaffinity”接收 pthread ID 和 一个 cpuset 作为参数。 当你在第一个参数中使用 0 时,调用线程 会受到影响

    【讨论】:

      【解决方案4】:

      请在下面找到特定 pthread 的 cpu-affinity 示例程序。

      请添加适当的库。

      double waste_time(long n)
      {
      
          double res = 0;
          long i = 0;
          while (i <n * 200000) {
              i++;
              res += sqrt(i);
          }
          return res;
      }
      
      void *thread_func(void *param)
      {
      
          unsigned long mask = 1; /* processor 0 */
      
          /* bind process to processor 0 */
          if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
              &mask) <0) {
              perror("pthread_setaffinity_np");
          }
      
          /* waste some time so the work is visible with "top" */
          printf("result: %f\n", waste_time(2000));
      
          mask = 2;   /* process switches to processor 1 now */
          if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
              &mask) <0) {
              perror("pthread_setaffinity_np");
          }
      
          /* waste some more time to see the processor switch */
          printf("result: %f\n", waste_time(2000));
      }
      
      
      int main(int argc, char *argv[])
      {
      
          pthread_t my_thread;
      
          if (pthread_create(&my_thread, NULL, thread_func, NULL) != 0) {
              perror("pthread_create");
          }
          pthread_exit(NULL);
      }
      

      使用 -D_GNU_SOURCE 标志编译上述程序。

      【讨论】:

      • 您的程序可以运行,但我发现有几个问题:1) pthread_setaffinity_np 需要一个 cpu_set_t,而不是无符号长。在传递给关联函数之前,应该使用 CPU_SET、CPU_ZERO 等宏来操作掩码 2) 最后,您不需要使用 pthread_create 启动新线程来运行代码的主要部分
      【解决方案5】:

      调度程序将根据需要更改 cpu 亲和性;要永久设置它,请参阅 /proc 文件系统中的 cpuset。

      http://man7.org/linux/man-pages/man7/cpuset.7.html

      或者您可以编写一个简短的程序,使用 sched_setaffinity 定期(每隔几秒)设置 cpu 亲和性

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-19
        • 2014-08-30
        • 1970-01-01
        • 1970-01-01
        • 2022-12-05
        相关资源
        最近更新 更多