Windows API 呼び出し SetThreadAffinityMask を使用してスレッドを 1 つの NUMA ノードにロックする小さなテスト プログラムを作成しました。GetNumaNodeProcessorMask API 呼び出しでノードの CPU ビットマスクを取得し、そのビットマスクを GetCurrentThread によって返されたスレッド ハンドルと共に SetThreadAffinityMask に渡します。これが私のコードの大幅に簡略化されたバージョンです:
// 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 への 2 回目の同一の呼び出しによって返されたマスクを出力しました。これはノード マスクと一致します。
ただし、DoWork 関数の実行時にリソース モニターを監視すると、表面上はバインドされているコアだけでなく、すべてのコアに作業が分割されます。SetThreadAffinityMask を使用しているときに見逃した可能性のあるトリップアップはありますか? 私は Windows 7 Professional 64 ビットを実行しており、DoWork 関数には OpenMP で並列化されたループが含まれており、3 つの非常に大きな配列の要素に対して操作を実行します (結合してもノードに収まります)。
編集: David Schwartz の回答を拡張するために、Windows では、OpenMP で生成されたスレッドは、それらを生成したスレッドのアフィニティを継承しません。問題は、SetThreadAffinityMask ではなく、それにあります。