创建线程时设置CPU关联

时间:2014-07-09 05:19:49

标签: c++ c multithreading c++11 pthreads

我想创建一个C ++ 11线程,我想让它在我的第一个核心上运行。我发现pthread_setaffinity_npsched_setaffinity可以更改线程的CPU关联,并将其迁移到指定的CPU。但是,在线程运行后,此关联性规范会发生更改。

如何创建具有特定CPU关联性的C ++ 11线程(cpu_set_t对象)?

如果在初始化C ++ 11线程时无法指定关联,如何在C中使用pthread_t

我的环境是Ubuntu上的G ++。感谢一段代码。

4 个答案:

答案 0 :(得分:19)

我很遗憾成为"神话破坏者"在这里,设置线程亲和性非常重要,随着时间的推移它变得越来越重要,因为我们所使用的系统本质上变得越来越多的NUMA(非统一内存架构)。 如今,即使是一个简单的双插槽服务器也会将RAM单独连接到每个插槽,并且从插槽到其自己的RAM访问存储器与相邻处理器插槽(远程RAM)的存储器的差异很大。在不久的将来,处理器正在进入市场,其中内部核心集合本身就是NUMA(用于单独核心组的独立存储器控制器等)。 我没有必要在这里重复其他人的工作,只需寻找" NUMA和线程亲和力"在线 - 您可以从其他工程师的多年经验中学习。

不设置线程亲和力实际上等于"希望" OS调度程序将正确处理线程关联。让我解释: 您有一个带有一些NUMA节点(处理和内存域)的系统。你启动一个线程,线程用内存做一些事情,例如malloc一些内存然后进行处理等现代操作系统(至少Linux,其他可能也是)到目前为止做得很好,默认情况下,内存是从运行线程的CPU的同一域分配(如果可用) 。 来吧,分时操作系统(所有现代操作系统)都会让线程进入休眠状态。当线程重新进入运行状态时,它可以在任何系统核心上运行(因为你没有为它设置一个亲和力掩码),系统越大,它被唤醒的可能性越大"在远离以前分配或使用的内存的CPU上。现在,您的所有内存访问都是远程的(不确定这对您的应用程序性能意味着什么?了解有关NUMA系统上的远程内存访问的更多信息)

因此,总而言之,在具有更重要的体系结构的系统上运行代码时,亲和性设置界面非常重要 - 这种体系正在迅速成为任何系统"这些日子。一些线程运行时环境/库允许在运行时控制它而无需任何特定的编程(参见OpenMP,例如在英特尔的KMP_AFFINITY环境变量的实现中) - 对于C ++ 11实现者来说,它是正确的。在其运行时库和语言选项中包含类似的机制(在此之前,如果您的代码旨在用于服务器,我强烈建议您在代码中实现关联控制)

答案 1 :(得分:2)

是的,有办法做到。我在此博客link

上遇到了这种方法

并且,此问题的所有其他答案都没有示例。这是编写代码的方法

  std::vector<std::thread> threads(num_threads);
  for (unsigned i = 0; i < num_threads; ++i) {
    threads[i] = std::thread([&iomutex, i] {
    std::this_thread::sleep_for(std::chrono::milliseconds(900));
      }
    });

    // Create a cpu_set_t object representing a set of CPUs. Clear it and mark
    // only CPU i as set.
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(i, &cpuset);
    int rc = pthread_setaffinity_np(threads[i].native_handle(),
                                    sizeof(cpu_set_t), &cpuset);
    if (rc != 0) {
      std::cerr << "Error calling pthread_setaffinity_np: " << rc << "\n";
    }
  }

整个功劳应归功于博客作者Eli endersky,并且链接粘贴在上方。

答案 2 :(得分:1)

在C ++ 11中,您无法在创建线程时设置线程关联(除非线程中运行的函数单独执行),但是一旦创建了线程,您就可以通过任何本机设置亲和性通过获取线程的本机句柄(thread.native_handle())来获得接口,因此对于Linux,您可以通过以下方式获取pthread id:

pthread_t my_thread_native = my_thread.native_handle();

然后你可以使用在my_thread_native中传递的任何pthread调用,它需要pthread线程id。

请注意,大多数线程工具都是特定于实现的,即pthreads,Windows线程,其他操作系统的本机线程都有自己的接口和类型,这部分代码不会非常便携。

答案 3 :(得分:-7)

搜索一段时间后,我们似乎无法在创建C ++ thread时设置CPU亲和力。

原因是,在创建线程时, NO NEED 指定了亲和力。那么,为什么要在语言中使它成为可能。

说,我们希望将工作负载f()绑定到CPU0。我们可以通过调用pthread_setaffinity_np来改变与实际工作负载之前的CPU0 的亲和力。

但是,我们 CAN 指定在C中创建线程时的亲和力。(感谢Tony D的评论)。 例如,以下代码输出&#34; Hello pthread&#34;。

void *f(void *p) {
  std::cout<<"Hello pthread"<<std::endl;
}

cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(0, &cpuset);
pthread_attr_t pta;
pthread_attr_init(&pta);
pthread_attr_setaffinity_np(&pta, sizeof(cpuset), &cpuset);
pthread_t thread;
if (pthread_create(&thread, &pta, f, NULL) != 0) {
    std::cerr << "Error in creating thread" << std::endl;
}
pthread_join(thread, NULL);
pthread_attr_destroy(&pta);