Критические секции и спин-блокировка
Когда поток пытается войти в критическую секцию, занятую другим потоком, он не медленно приостанавливается. А это значит, что поток переходит из пользовательского режима в режим ядра (на что затрачивается около 1000 тактов процессора). Цена такого перехода чрезвычайно высока. На многопроцессорной машине поток, владеющий ресурсом, может выполняться на другом процессоре и очень быстро освободить ресурс. Тогда появляется вероятность, что ресурс будет освобожден еще до того, как вызывающий поток завершит переход в режим ядра. В итоге уйма процессорного времени будет потрачена впустую.
Microsoft повысила быстродействие критических секций, включив в них спин-блокировку Теперь, когда Вы вызываете EnterCriticalSection, она выполняет заданное число циклов спин-блокировки, пытаясь получить доступ к ресурсу и лишь в том случае, когда все попытки закапчиваются неудачно, функция переводит поток в режим ядра, где он будет находиться в состоянии ожидания.
Для использования спин-блокировки в критической секции нужно инициализировать счетчик циклов, вызвав:
BOOL InitalizeCriticalSectionAndSpinCount( PCRITICAL_SECTION pcs, DWORD dwSpinCount);
Как и в InitializeCriticalSection, первый параметр этой функции — адрес структуры критической секции. Но во втором параметре, dwSpinCount, передается число циклов спин-блокировки при попытках получить доступ к ресурсу до перевода потока в состояние ожидания. Этот параметр может принимать значения от 0 до 0x00FFFFFF. Учтите, что на однопроцессорной машине значение параметра dwSpinCount игнорируется и считается равным 0. Дело в том, что применение спин-блокировки в такой системе бессмысленно: поток, владеющий ресурсом, не сможет освободить его, пока другой поток "крутится" в циклах спин-блокировки.
Вы можете изменить счетчик циклов спин-блокировки вызовом:
DWORD SetCriticalSectionSpinCount( PCRITICAL_SECTION pcs, DWORD dwSpinCount);
И в этой функции значение dwSpinCount на однопроцессорной машине игнорируется.
Па мой взгляд, используя критические секции, Вы должны всегда применять спин-блокировку — терять Вам просто нечего. Moгут возникнуть трудности в подборе значения dwSpinCount, по здесь нужно просто поэкспериментировать. Имейте в виду, что для критической секции, стоящей па страже динамической кучи Вашего процесса, этот счетчик равен 4000.
Как реализовать критические секции с применением спин-блокировки, я покажу в главе 10.