创建线程时设置CPU关联

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

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

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

我的环境是Ubuntu上的G ++。 一段代码表示赞赏。

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

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

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

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

pthread_t my_thread_native = my_thread.native_handle();

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

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

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

原因是,创建线程时无需指定关联。 那么,为什么要在语言中使它成为可能呢。

比如说,我们希望将工作负载f()绑定到CPU0。 我们可以通过调用pthread_setaffinity_np在实际工作负载之前更改与CPU0的亲缘关系。

但是,我们可以在C中创建一个线程时指定亲和力。(感谢Tony D的评论)。 例如,以下代码输出“Hello pthread”。

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