On my system, SetThreadAffinityMask seems to mitigate the problem. There is still some imbalance, apparently due to the fact that one core has less time than another, but it is not so strong.
Windows seems reluctant to move these threads between cores; they rarely change core after the first second or so. If the threads are distributed unevenly between the cores, the flow time reflects this.
This is the code I used to test affinity masks:
#include <Windows.h> #include <stdio.h> DWORD WINAPI ThreadStart(LPVOID arg) { DWORD pn1, pn2; printf("Thread %u on processor %u\n", GetThreadId(GetCurrentThread()), pn1 = GetCurrentProcessorNumber()); // The problem comes back if you enable this line // SetThreadAffinityMask(GetCurrentThread(), -1); for (;;) { for (int i = 0; i < 10000; i++); pn2 = GetCurrentProcessorNumber(); if (pn2 != pn1) { pn1 = pn2; printf("Thread %u on processor %u\n", GetThreadId(GetCurrentThread()), pn1); } } return 0; } int main(int argc, char ** argv) { SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS); SYSTEM_INFO si; GetSystemInfo(&si); for (DWORD i = 0; i < si.dwNumberOfProcessors; i++) { SetThreadAffinityMask(CreateThread(NULL, 0, &ThreadStart, NULL, 0, NULL), 1 << i); SetThreadAffinityMask(CreateThread(NULL, 0, &ThreadStart, NULL, 0, NULL), 1 << i); } Sleep(INFINITE); return 0; }
This approach also seems to mitigate the problem, although perhaps not as efficiently:
#include <Windows.h> #include <stdio.h> DWORD WINAPI ThreadStart(LPVOID arg) { for (;;); return 0; } int main(int argc, char ** argv) { SYSTEM_INFO si; GetSystemInfo(&si); for (DWORD i = si.dwNumberOfProcessors * 2; i > 0; i--) { CreateThread(NULL, 0, &ThreadStart, NULL, 0, NULL); } for (;;) { SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS); Sleep(100); SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); } return 0; }
I suspect that we are looking at some kind of energy saving measure based on the assumption that low priority threads do not need a fair schedule. (Perhaps installing a thread or a low priority process says, "I don't care how much CPU I get.")