我编写了一个小测试程序,我尝试使用Windows API调用SetThreadAffinityMask将线程锁定到单个NUMA节点。我使用GetNumaNodeProcessorMask API调用检索节点的CPU位掩码,然后将该位掩码传递给SetThreadAffinityMask以及GetCurrentThread返回的线程句柄。这是我的代码的大大简化版本:
// Inside a function called from a boost::thread
unsigned long long nodeMask = 0;
GetNumaNodeProcessorMask(1, &nodeMask);
HANDLE thread = GetCurrentThread();
SetThreadAffinityMask(thread, nodeMask);
DoWork(); // make-work function
我当然检查API调用是否在我的代码中返回0,并且我还打印出了NUMA节点掩码,这正是我所期望的。我也遵循了其他地方给出的建议,并打印出第二次调用SetThreadAffinityMask返回的掩码,它与节点掩码匹配。
但是,从DoWork函数执行时观察资源监视器开始,工作将在所有核心之间进行分割,而不仅仅是表面上绑定的核心。使用SetThreadAffinityMask时,我可能错过了任何绊倒吗?我正在运行Windows 7 Professional 64位,而DoWork函数包含一个与OpenMP并行化的循环,它对三个非常大的数组(它们组合在一起仍然能够适应节点)的元素执行操作。
编辑:为了扩展David Schwartz给出的答案,在Windows上,任何使用OpenMP生成的线程都不会继承产生它们的线程的亲和力。问题在于,而不是SetThreadAffinityMask。
答案 0 :(得分:2)
您是否确认了其关联掩码在另一个numa节点的核心上运行的特定线程?否则,它按预期工作。您正在一个线程上设置处理器掩码,然后观察线程的组的行为。