Синхронизация потоков в операционной системе Windows, страница 14

Событие напоминает общий для нескольких процессов флаг, однако действует несколько сложнее, чем обычная переменная общего доступа. События удобно применять в случае, если один поток хочет оповестить другой поток о том, что он завершил ту или иную операцию и готов к дальнейшим действиям. Мануалыюе событие (manual event) остается в установленном состоянии до тех пор, пока ваша программа явно сбросит его. Единичное событие (single event) автоматически сбрасывается в момент, когда хотя бы один из потоков обнаружит, что оно установлено. Вызов PulseEvent устанавливает событие на время, необходимое для того, чтобы об изменении состояния события узнали все ожидающие его потоки, а затем автоматически сбрасывает событие.

Мьюотекс сигнализирует о том, что поток эксклюзивно владеет тем или иным ресурсом. В любой момент времени мьютексом владеет не более одного потока. Если ноток является хозяином мьютекса, он может повторно завладеть им любое количество раз. Поток сохраняет за собой права на владение мьютексом до тех пор, пока он не обратится к ReleaseMutex. Если перед этим поток завладел мьютексом несколько раз, чтобы освободить мьютекс, он должен обратиться к ReleaseMutex такое же количество раз. Система будет отказывать всем остальным потокам, пытающимся завладеть мьютексом, до тех пор, пока поток-владелец мьютекса не иынолнит завершающее обращение к ReleaseMutex.

Если вы хотите использовать технологию наподобие мьютекса в рамках одного процесс;», вы можете использовать критическую секцию. Критическая секция обеспечивает большую эффективность, чем мьютекс. Для своих функций критическая секция использует специальную переменную вашей программы (тип переменной — CRITICAL_SECTION), которая выполняет функции дорожного полицейского, управляющего движением на узком участке дороги. Когда поток обращается к EnterCriticalSection, он получает право выполнить критический участок кода. Если после этого другой поток попытается выполнить EnterCriticalSection, его выполнение будет блокировано до тех пор, пока первый поток не обратится к LeaveCriticalSection. Если поток, желающий выполнить критический участок кода, не желает, чтобы его выполнение было блокировано в случае, если этот участок уже занят другим потоком, он может вместо EnterCritica1Secion использовать вызов TryCriticalSection.

Помимо мьютексов и критических секций для ограничения доступа к ресурсам можно использовать семафоры. В отличие от мьютексов и критических секций, семафор разрешает одновременное использование ресурса для нескольких потоков. Однако при этом максимальное количество потоков, одновременно обладающих доступом к ресурсу, ограничивается, Каждый семафор обладает связанным с ним счетчиком. Каждый раз, когда поток получает доступ к семафору, значение счетчика уменьшается на единицу. Когда значение счетчика семафора становится равным нулю, семафор становится недоступным для остальных потоков. Чтобы воспользоваться семафором, остальные потоки обязаны ждать до тех пор, пока один из потоков, обладающих доступом к семафору, не обратится к вызову ReleaseSemaphore. В результате этого вызова значение счетчика увеличится на единицу, и семафором сможет воспользоваться какой-либо другой поток.

Когда следует использовать тот или иной метод синхронизации? Это зависит от того, какие цели преследует ваша программа. Если необходимо оповестить несколько потоков о том, что подготовка исходных данных завершена и потоки могут приступить к их обработке, скорее всего, удобнее воспользоваться событием. Чтобы предотвратить одновременный доступ к файлу нескольких потоков, удобнее использовать мьютекс (или критическую секцию в случае, если речь идет о потоках, принадлежащих одному процессу). Чтобы ограничить количество сетевых запросов, которые имеет право инициировать одна рабочая станция, удобнее использовать семафор.