Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
os_a_win.doc
Скачиваний:
15
Добавлен:
17.11.2019
Размер:
715.26 Кб
Скачать

Семафоры

Семафор является более сложным объектом. В нем хранится переменная целого типа, которая может принимать значения от 0 до некоторого заданного максимально значения. Семафор занят, если значение его переменной равно 0 и свободен, если оно больше нуля. У объектов семафор всегда присутствует побочный эффект ожидания – успешный вызов Wait-функции на семафоре обязательно уменьшает значение счетчика на 1.

Такой объект удобно использовать, если мы хотим учитывать число каких-либо ресурсов. Например, у нас есть процесс-сервер, в памяти которого есть место для хранения 5 клиентских запросов. При помещении запросов в память сервера клиенты будут увеличивать счетчик семафора на 1, и он будет отражать число запросов в буфере. Более 5 запросов поместить не удастся, поскольку клиент не сможет увеличить счетчик семафора. Поток сервера может использовать ожидание на семафоре для того, чтобы определить есть ли у него работа: если счетчик равен нулю (запросов нет) поток будет находиться в состоянии ожидания, а если запросы есть – семафор свободен и сервер сможет начать их обработку.

Объект ядра семафор создается вызовом функции CreateSemaphore:

HANDLE CreateSemaphore(

LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD

LONG lInitialCount, // initial count

LONG lMaximumCount, // maximum count

LPCTSTR lpName // object name

);

С помощью параметров lInitialCount и lMaximumCount мы задаем соответственно начальное и максимальное значения счетчика.

Получить доступ к именованному семафору мы можем с помощью функции OpenSemaphore.

Значение счетчика семафора можно увеличивать с помощью функции ReleaseSemaphore:

BOOL ReleaseSemaphore(

HANDLE hSemaphore, // handle to semaphore

LONG lReleaseCount, // count increment amount

LPLONG lpPreviousCount // previous count

);

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

Значение счетчика перед изменением помещается в переменную, на которую указывает параметр lpPreviousCount. В нашем примере клиент мог бы использовать его, чтобы определить в какую именно область памяти он должен записать свой запрос. Если это значение не требуется, то можно передать функции указатель NULL.

Мьютексы

Объекты типа мьютекс используют для получения эксклюзивного доступа к какому-либо ресурсу. По действию этот объект во многом напоминает критическую секцию, однако в отличие от нее он может работать с потоками из разных процессов, и при работе с ним можно использовать все возможности Wait-функций которых нет у критических секций: задавать время ожидания, использовать совместно с другими объектами синхронизации ядра.

Содержанием объекта мьютекс является идентификатор захватившего его процесса и счетчик рекурсии. Мьютекс находится в свободном состоянии, если он не захвачен никаким потоком. При успешном вызове Wait-функции на мьютексе в нем записывается идентификатор процесса, и объект переходит в занятое состояние. Другие потоки не смогут захватить его до тех пор, пока он не будет освобожден. Счетчик рекурсии будет использоваться в том случае, если мьютекс повторно попытается захватить тот же процесс – при этом доступ к объекту будет получен, а значение счетчика рекурсии увеличено. Если один поток захватывает мьютекс несколько раз, то и освободить он его должен такое же число раз.

Для использования мьютекса его необходимо создать с помощью функции CreateMutex:

HANDLE CreateMutex(

LPSECURITY_ATTRIBUTES lpMutexAttributes, // SD

BOOL bInitialOwner, // initial owner

LPCTSTR lpName // object name

);

При создании мьютекса мы можем сразу захватить его, передав в параметре bInitialOwner значение TRUE.

Открыть существующий мьютекс по имени может функция OpenMutex.

Для работы с мьютексом нам необходимы две операции – захват и освобождение. Захват мьютекса является побочным эффектом Wait-функций, и никакой специальной функции для этого не предусмотрено. Освобождается мьютекс с помощью функции ReleaseMutex:

BOOL ReleaseMutex(

HANDLE hMutex // handle to mutex

);

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

Интересная ситуация возникает если поток, захвативший мьютекс прекращает свое существование, не освободив объект. В этом случае Windows автоматически освобождает мьютекс. Если в это время этот объект ждут другие потоки, то один из них сможет захватить его. Однако Wait-функция этого потока вернет не значение WAIT_OBJECT_0 а значение WAIT_ABADONED, информируя, что отказ от мьютекса произошел некорректно.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]