これに使用するコードを次に示します (他の場所で定義されているいくつかの定数を削除するために少し調整されています)。最初に通常どおりスレッドを作成し、次にスレッド内から以下を呼び出すことに注意してくださいSetAffinityAndRelocateStack()
。これは、独自のスタックを作成しようとするよりもはるかに優れていると思います。スタックは、底に達した場合に成長するための特別なサポートを備えているためです。
新しく作成されたスレッドを外部から操作するようにコードを変更することもできますが、競合状態が発生する可能性があるため (スレッドがスタックへの I/O を実行する場合など)、お勧めしません。
void* PreFaultStack()
{
const size_t NUM_PAGES_TO_PRE_FAULT = 50;
const size_t size = NUM_PAGES_TO_PRE_FAULT * numa_pagesize();
void *allocaBase = alloca(size);
memset(allocaBase, 0, size);
return allocaBase;
}
void SetAffinityAndRelocateStack(int cpuNum)
{
assert(-1 != cpuNum);
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(cpuNum, &cpuset);
const int rc = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
assert(0 == rc);
pthread_attr_t attr;
void *stackAddr = nullptr;
size_t stackSize = 0;
if ((0 != pthread_getattr_np(pthread_self(), &attr)) || (0 != pthread_attr_getstack(&attr, &stackAddr, &stackSize))) {
assert(false);
}
const unsigned long nodeMask = 1UL << numa_node_of_cpu(cpuNum);
const auto bindRc = mbind(stackAddr, stackSize, MPOL_BIND, &nodeMask, sizeof(nodeMask), MPOL_MF_MOVE | MPOL_MF_STRICT);
assert(0 == bindRc);
PreFaultStack();
// TODO: Also lock the stack with mlock() to guarantee it stays resident in RAM
return;
}