Совместимость потоков с Windows, MSVC и OpenMP

Я хочу привязать потоки в моем коде к каждому физическому ядру. С GCC я успешно сделал это с помощью sched_setaffinity, поэтому мне больше не нужно устанавливать export OMP_PROC_BIND=true. Я хочу сделать то же самое в Windows с MSVC. Windows и Linux с использованием другой топологии потоков. Linux рассеивает потоки, а окна используют компактную форму. Другими словами, в Linux с четырьмя ядрами и восемью гиперпотоками мне нужно привязать потоки к первым четырем процессорам. В Windows я устанавливаю их для каждого другого процессора.

Я успешно сделал это, используя SetProcessAffinityMask. Я могу видеть из диспетчера задач Windows, когда я нажимаю правой кнопкой мыши на процессы и нажимаю "Установить аффинность", что каждый другой процессор установлен (0, 2, 4, 6 в моей восьми гиперпотоковой системе). Проблема в том, что эффективность моего кода нестабильна при запуске. Иногда он почти постоянный, но большую часть времени он имеет большие изменения. Я изменил приоритет на высокий, но это не имеет никакого значения. В Linux эффективность стабильна. Может быть, Windows все еще переносит потоки? Есть ли что-то еще, что мне нужно сделать, чтобы связать потоки в Windows?

Вот код, который я использую

#ifdef _WIN32   
HANDLE process;
DWORD_PTR processAffinityMask = 0;
//Windows uses a compact thread topology.  Set mask to every other thread
for(int i=0; i<ncores; i++) processAffinityMask |= 1<<(2*i);        
//processAffinityMask = 0x55;
process = GetCurrentProcess();
SetProcessAffinityMask(process, processAffinityMask);
#else
cpu_set_t  mask;
CPU_ZERO(&mask);
for(int i=0; i<ncores; i++) CPU_SET(i, &mask);      
sched_setaffinity(0, sizeof(mask), &mask);       
#endif

Изменить: вот код, который я использовал сейчас, который, кажется, стабилен в Linux и Windows

    #ifdef _WIN32   
    HANDLE process;
    DWORD_PTR processAffinityMask;
    //Windows uses a compact thread topology.  Set mask to every other thread
    for(int i=0; i<ncores; i++) processAffinityMask |= 1<<(2*i);
    process = GetCurrentProcess();
    SetProcessAffinityMask(process, processAffinityMask);
    #pragma omp parallel 
    {
        HANDLE thread = GetCurrentThread();
        DWORD_PTR threadAffinityMask = 1<<(2*omp_get_thread_num());
        SetThreadAffinityMask(thread, threadAffinityMask);
    }
    #else
    cpu_set_t  mask;
    CPU_ZERO(&mask);
    for(int i=0; i<ncores; i++) CPU_SET(i, &mask);
    sched_setaffinity(0, sizeof(mask), &mask);
    #pragma omp parallel 
    {
       cpu_set_t  mask;
       CPU_ZERO(&mask);
       CPU_SET(omp_get_thread_num(),&mask);
       pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask); 
    }
    #endif

Ответ 1

Вы должны использовать функцию SetThreadAffinityMask (см. ссылка MSDN). Вы устанавливаете маску процесс.

Вы можете получить thread ID в OpenMP с помощью этого кода:

int tid = omp_get_thread_num();

Однако приведенный выше код предоставляет OpenMP internal thread ID, а не систему thread ID. В этой статье объясняется более подробно:

http://msdn.microsoft.com/en-us/magazine/cc163717.aspx

если вам нужно явно работать с этими trheads - используйте явный affinity type, как описано в этой документации Intel:

https://software.intel.com/sites/products/documentation/studio/composer/en-us/2011Update/compiler_c/optaps/common/optaps_openmp_thread_affinity.htm