Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаб-07(Shinhron) Синхронизация потоков.DOC
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
327.68 Кб
Скачать

2.2.Семафоры

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

Допустим, у компьютера три последовательных порта. Значит, одновременно ими могут пользоваться не более, чем три потока; каждый порт может быть закреплен за одним потоком. Для мониторинга занятости последовательных портов необходимо создать семафор со счетчиком, равным 3 (три последовательных порта). При этом нужно учитывать, что семафор считается свободным, если его счетчик ресурсов больше нуля, и занятым, если счетчик равен нулю. При каждом вызове из потока WaitForSingleObject с передачей ей описателя семафора система проверяет: больше ли нуля счетчик ресурсов у данного семафора. Если да, уменьшает счетчик на единицу и "будит" поток. Если при вызове WaitForSingleObject счетчик семафора оказался обнулен, система оставляет поток неактивным до того, как другой поток освободит семафор (т.е. увеличит его счетчик ресурсов).

Поскольку на счетчик ресурсов семафора могут влиять несколько потоков, семафоры - в отличие от критических разделов и объектов mutex - не передаются во владение какому-либо потоку. А, значит, один поток может ждать объект "семафор" (уменьшив его счетчик ресурсов), а другой поток освободить семафор (и тем самым увеличить его счетчик ресурсов).

Семафор создается вызовом функции GreateSemaphore:

HANDLE GreatSemaphore (LPSECURITY_ATTRIBUTES lpsa,

LONG cSemInitial, LONG cSemMax, LPTSTR lpszSemName);

Эта функция создает семафор, максимальное значение счетчика которого может достигать cSemMax. В рассмотренном примере в этот параметр следовало бы поместить число 3 (три последовательных порта). Параметр cSemInitial позволяет задать начальное состояние счетчика. При запуске системы все последовательные порты будут свободны, значит и сюда надо занести число 3. Но если при инициализации операционной системы нужно указать, что все последовательные порты заняты, параметр cSemInitial обнуляется.

Последний параметр функции - lpszSemName - присваивает семафору имя в виде строки. В дальнейшем это имя используется для получения описателя семафора из других процессов с помощью CreateSemaphore или OpenSemaphore:

HANDLE OpenSemaphore (DWORD fdwAccess, BOOL fInherit,

LPTSTR lpszName);

По семантике эта функция идентична функции OpenMutex. Чтобы освободить семафор (увеличить его счетчик ресурсов), вызывается функция ReleaseSemaphore:

BOOL ReleaseSemaphore (HANDLE hSemaphore, LONG cRelease,

LPLONG lplPrevious);

Эта функция похожа на функцию ReleaseMutex, но имеет ряд отличий. Во-первых, любой поток может вызвать ее когда угодно, поскольку объекты "семафор" не принадлежат лишь какому-то одному потоку. Во-вторых, с ее помощью счетчик ресурсов, принадлежащий семафору, можно увеличить более, чем на единицу единовременно. Параметр cRelease как раз и определяет, какими порциями должен освобождаться семафор. Например, имеется приложение, копирующее данные из одного последовательного порта в другой. Оно должно дважды запрашивать ресурсы у семафора, соответственно дважды вызывая функцию WaitForSingleObject. Однако освободить оба ресурса программа может через один вызов функции ReleaseSemaphore:

// Запрашиваются два последовательных порта

WaitForSingleObject (g_hSemSerialPort, INFINITE);

WaitForSingleObject (g_hSemSerialPort, INFINITE);

...................................................................................................................

// Работа с последовательными портами

....................................................................................................................

// Освобождение последовательных портов для доступа к ним других приложений

ReleaseSemaphore(g_hSemSerialPort, 2, NULL);

Последний параметр функции ReleaseSemaphore- lplPrevious- указатель на переменную типа long, куда заносится значение счетчика ресурсов, предшествующее тому, что получается после увеличения его на величину cRelease. Если это значение не требуется, можно просто передать в этом параметре NULL.