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

За исключением критической секции, все объекты синхронизации работают очень похоже. Чтобы создать тот или иной объект синхронизации, следует обратиться к соответствующему вызову создания объекта (например, CreateMutex или CreateSemaphore). Этот вызов либо создает новый объект синхронизации, либо открывает уже существующий, который обладает указанным вами именем. Если вы намерены открыть уже существующий объект синхронизации, вы можете использовать для этого специальный вызов (например, OpenMutex или OpenSemaphore). В любом случае вы получаете дескриптор объекта синхронизации. Если вы рассчитываете, что создаваемый вами объект будет использоваться только текущим процессом и его дочерними процессами, вы можете не указывать имя объекта при его создании. Дочерние процессы могут наследовать дескрипторы объектов синхронизации, созданные родительским процессом.

В качестве первого атрибута вызову Create объекта синхронизации передается указатель на структуру SECURITY_ATTRIBUTE, в которой содержится информация о доступе к новому дескриптору. Структура содержит флаг, определяющий, могут ли дочерние процессы наследовать этот дескриптор, а также указатель на дескриптор безопасности, который можно не указывать. Если вы хотите использовать дескриптор безопасности по умолчанию, вы можете в качестве указателя на него подставить в структуру значение NULL. Если вас также не волнует значение флага, определяющего режим наследования, в качестве первого аргумента вы можете передать функции создания объекта синхронизации значение NULL. В этом случае будет использоваться значение флага по умолчанию. Чтобы присвоить значение дескриптору безопасности, используйте функцию ImtializeSecurityDescriptor совместно с другими вызовами, предназначенными для управления уровнем доступа.

Если вы хотите, чтобы доступом к объекту синхронизации обладали взаимонезависимые процессы, вы должны присвоить этому объекту имя. Имя — это последовательность символов с учетом регистра. В состав имени не может входить символ обратной косой (\). Имена всех объектов синхронизации принадлежат к единому пространству имен, поэтому нельзя присвоить одинаковое имя, например, мьютексу и семафору.

Следить за состоянием объектов синхронизации можно при помощи специальных вызовов, самый простой из которых — WaitForSingleObject. Эта функция проверяет, находится ли объект в сигнальном состоянии. Как только это произошло, функция немедленно возвращает управление вызвавшей программе и сообщает ей об изменении состояния объекта. Сигнальное состояние для разных объектов синхронизации обозначает разное. Событие переходит в сигнальное состояние в случае, если оно установлено. Мьютекс переходит в сигнальное состояние в случае, если он освободился. А семафор — в случае, если значение его счетчика отлично от нуля. Функция WaitForSingleObject может ожидать изменения состояния интересующего вас объекта сколь угодно долгое время, однако эту же функцию можно использовать для того, чтобы только проверить состояние объекта и немедленно продолжить работу основной программы.

Помимо WaitForSingleObject существуют также другие вызовы, которые можно использовать для слежения за состоянием объектов синхронизации. Например, вызов WaitForMu1t1p1eObjects позволяет следить за состоянием сразу нескольких объектов синхронизации. В зависимости от переданных ей аргументов эта функция вернет управление вызвавшей программе либо в момент, когда свое состояние изменят все интересующие вас объекты, либо когда в сигнальное состояние перейдет хотя бы один из них. Существуют также некоторые другие вызовы, которые работают подобно WaitForSingleObject и WaitForMu1tip1eObjects с некоторыми отличиями.

Изменить состояние события можно в любой момент при помощи специальных вызовов. Мьютексы и семафоры изменяют состояние в зависимости от того, владеют ли ими какие-либо потоки. Освободить мьютекс можно при помощи вызова ReleaseMutex. Семафор освобождается при помощи вызова ReleaseSemaphore.