Для Windows критические секции легче, чем мьютексы.
Мьютексы могут быть разделены между процессами, но всегда приводят к системному вызову ядра, которое имеет некоторые издержки.
Критические секции могут использоваться только в рамках одного процесса, но их преимущество заключается в том, что они переключаются в режим ядра только в случае конкуренции - неконтролируемые запросы, которые должны быть распространены, невероятно быстрые. В случае разногласий они входят в ядро, чтобы ожидать некоторый примитив синхронизации (например, событие или семафор).
Я написал быстрый пример приложения, в котором сравнивается время между ними. В моей системе для 1 000 000 несанкционированных приобретений и выпусков мьютекс занимает более одной секунды. Критический раздел занимает ~ 50 мс на 1000000 приобретений.
Вот тестовый код, я запустил его и получил аналогичные результаты, если мьютекс первый или второй, поэтому других эффектов мы не видим.
HANDLE mutex = CreateMutex(NULL, FALSE, NULL);
CRITICAL_SECTION critSec;
InitializeCriticalSection(&critSec);
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
LARGE_INTEGER start, end;
// Force code into memory, so we don't see any effects of paging.
EnterCriticalSection(&critSec);
LeaveCriticalSection(&critSec);
QueryPerformanceCounter(&start);
for (int i = 0; i < 1000000; i++)
{
EnterCriticalSection(&critSec);
LeaveCriticalSection(&critSec);
}
QueryPerformanceCounter(&end);
int totalTimeCS = (int)((end.QuadPart - start.QuadPart) * 1000 / freq.QuadPart);
// Force code into memory, so we don't see any effects of paging.
WaitForSingleObject(mutex, INFINITE);
ReleaseMutex(mutex);
QueryPerformanceCounter(&start);
for (int i = 0; i < 1000000; i++)
{
WaitForSingleObject(mutex, INFINITE);
ReleaseMutex(mutex);
}
QueryPerformanceCounter(&end);
int totalTime = (int)((end.QuadPart - start.QuadPart) * 1000 / freq.QuadPart);
printf("Mutex: %d CritSec: %d\n", totalTime, totalTimeCS);