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

Вызов MaitForSingleObject возвращает несколько различных значений в зависимости от результатов проверки состояния объекта синхронизации. Если объект перешел в сигнальное состояние, функция возвращает значение WAIT_OBJECT_0. Если указанный при вызове период времени истек, а объект все еще не перешел в сигнальное состояние, функция возвращает WAIT_TIMEOUT. Наконец, если процесс, владеющий мьютексом, завершает работу с открытым мьютексом, система передает этот мьютекс ожидающему потоку, а вызов возвращает значение WAIT_ABANDONED.

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

Блокированные вызовы

Если вы хотите обратиться к переменной без опасений, что в момент обращения операционная система передаст управление другому потоку, вы можете воспользоваться одним из блокированных вызовов (interlocked call), которые являются частью Windows API. Блокированные вызовы перечислены в табл. 1. Вы можете использовать эти вызовы для безопасной работы с переменными в многопоточной среде, однако зачастую большинство встающих перед вами проблем, связанных с многопоточностью, удобнее решать при помощи событий, семафоров и мьютексов.

Блокированные вызовы                                                          Таблица 1.

Вызов

Назначение

InterlockedDecrement Interlockedlncrement InterlockedExchange

InterlockedExchangeAdd InterlockedCompareExchange

Вычитает единицу из блокированной переменной

Добавляет единицу к блокированной переменной

Меняет местами значение блокированной переменной и значение другой переменной

Добавляет значение к блокированной переменной

Сравнивает значение блокированной переменной с некоторым значением и в случае, если значения равны, меняет местами значение блокированной переменной и значение некоторой другой переменной

Блокированные вызовы из табл. 1 работают с 32-битными значениями, выровненными по границе 32 бит. Если вы намерены синхронизировать работу потоков, вы можете использовать обычную глобальную переменную. Если синхронизируется работа процессов, переменную необходимо поместить в общую память.

Наверное, самым полезным является вызов InterlockedCompareExchange. Блокированная переменная сравнивается с некоторым значением. Если переменная и значение равны, функция меняет местами значения блокированной переменной и любой другой переменной по вашему выбору. При этом вы можете быть уверенными в том, что в течение всей этой процедуры ни один другой поток не сможет получить доступ к блокированной переменной.

Например, если вы используете флаг tflag и хотите присвоить ему значение 1 только в случае, если этот флаг равен 0, вы можете написать следующий код:

PVOID var=(PVOID)&tflag;

PVOID newval=(PVOID)l;

PVOID compare=( PVOID)0;

InterlockedCompareExchange(&var, newval, compare);

if (newval=1) . . . ; // флаг был равен 1

else {

//флаг был равен 0, а сейчас он равен 1

. . .

       }

Подробнее о событиях