Критически важные объекты раздела
Объект критически важных разделов обеспечивает синхронизацию, аналогичную той, которая предоставляется объектом мьютекса, за исключением того, что критически важный раздел можно использовать только потоками одного процесса. Критически важные объекты разделов нельзя совместно использовать в процессах.
Объекты событий, мьютекса и семафора также можно использовать в однопроцессном приложении, но критически важные объекты разделов обеспечивают более быстрый, более эффективный механизм для синхронизации взаимоисключения (инструкция для конкретного процессора и задания). Как и объект мьютекса, критически важный объект раздела может принадлежать только одному потоку за раз, что делает его полезным для защиты общего ресурса от одновременного доступа. В отличие от объекта мьютекса, невозможно определить, был ли критический раздел оставлен.
Начиная с Windows Server 2003 с пакетом обновления 1 (SP1), потоки, ожидающие критически важного раздела, не получают критически важный раздел на основе первого выпуска. Это изменение значительно повышает производительность для большинства кода. Однако некоторые приложения зависят от упорядочения в первую очередь (FIFO) и могут работать плохо или не вообще в текущих версиях Windows (например, приложения, использующие критически важные разделы в качестве ограничения скорости). Чтобы обеспечить правильную работу кода, может потребоваться добавить дополнительный уровень синхронизации. Например, предположим, что у вас есть поток производителя и поток потребителя, которые используют критически важный объект раздела для синхронизации своей работы. Создайте два объекта события, по одному для каждого потока, чтобы сообщить о том, что он готов к продолжению другого потока. Поток потребителя будет ожидать, пока производитель сигнализирует о своем событии, прежде чем вводить критически важный раздел, и поток производителя будет ждать, пока поток потребителя сигнализирует о своем событии перед вводом критического раздела. После того как каждый поток покидает критически важный раздел, он сигнализирует о его событии, чтобы освободить другой поток.
Windows Server 2003 и Windows XP: потоки, ожидающие критического раздела, добавляются в очередь ожидания; они проснуты и обычно получают критически важный раздел в порядке, в котором они были добавлены в очередь. Однако если потоки добавляются в эту очередь с достаточно быстрой скоростью, производительность может снизиться из-за времени, необходимого для пробуждения каждого ожидающего потока.
Процесс отвечает за выделение памяти, используемой критическим разделом. Как правило, это делается путем простого объявления переменной типа CRITICAL_SECTION. Прежде чем потоки процесса смогут использовать его, инициализировать критически важный раздел с помощью функции InitializeCriticalSection или InitializeCriticalSectionAndSpinCount.
Поток использует функцию EnterCriticalSection или TryEnterCriticalSection для запроса владения критически важным разделом. Она использует функцию LeaveCriticalSection для освобождения владения критически важным разделом. Если объект критического раздела в настоящее время принадлежит другому потоку, EnterCriticalSection ожидает неограниченное время владения. В отличие от этого, когда объект мьютекса используется для взаимного исключения, функции ожидания принять указанный интервал времени ожидания. Функция tryEnterCriticalSection пытается ввести критически важный раздел, не блокируя вызывающий поток.
Если поток владеет критически важным разделом, он может выполнять дополнительные вызовы к EnterCriticalSection или TryEnterCriticalSection без блокировки выполнения. Это предотвращает взаимоблокировку потока во время ожидания критического раздела, которому он уже владеет. Чтобы освободить его владение, поток должен вызывать LeaveCriticalSection один раз за каждый раз, когда он вошел в критически важный раздел. Нет никаких гарантий в порядке, в котором потоки ожидания получат владение критически важным разделом.
Поток использует функцию InitializeCriticalSectionAndSpinCount или SetCriticalSectionSpinCount, чтобы указать число спинов для объекта критического раздела. Спиннинг означает, что при попытке потока получить критически важный раздел, который заблокирован, поток входит в цикл, проверяет, освобождается ли блокировка, и если блокировка не освобождена, поток переходит в спящий режим. В системах с одним процессором число спинов игнорируется, а число спинов критических разделов равно 0 (ноль). В системах с несколькими обработчиками, если критически важный раздел недоступен, вызывающий поток выполняет спину dwSpinCount раз перед выполнением операции ожидания на семафоре, связанном с критическим разделом. Если критически важный раздел становится свободным во время операции спина, вызывающий поток избегает операции ожидания.
Любой поток процесса может использовать функцию deleteCriticalSection для освобождения системных ресурсов, выделенных при инициализации объекта критического раздела. После вызова этой функции объект критического раздела не может использоваться для синхронизации.
Если объект критического раздела принадлежит, только другие затронутые потоки — это потоки, ожидающие владения в вызове EnterCriticalSection. Потоки, которые не ожидают, будут работать бесплатно.
Связанные разделы