Смекни!
smekni.com

Использование семафоров для синхронизации потоков (стр. 2 из 2)

Существующий семафор можно открыть функцией OpenSemaphore(), синтаксис которой следующий

HANDLE OpenSemaphore (DWORD dwAccessFlag, BOOL bInherit, LPCTSTR lpszSemName)

Параметры:

dwAccessFlag – указатель на требуемый тип доступа к семафору;

bInherit – определяет возможность наследования семафора другими процессами, создаваемые функцией CreateProcess();

lpszSemName– указатель на строку, содержащую имя открываемого семафора.

Возвращаемое значение. При успешном выполнении функция возвращает хэндл открытого семафора, в противном случае – возвращается NULL.

Флаги доступа могут принимать одно из трех значений:

Параметр Описание
SEMAPHORE_ALL_ACCESS Устанавливает все возможное флаги доступа для данного семафора
SEMAPHORE_MODIFY_STATE Разрешает изменение счетчика ресурсов в функции ReleaseSemaphore()
SYNCHONIZE Разрешает использование в любой из ожидающих функций сигнала об изменении состояния семафора

Для увеличения значения счетчика семафора приложение должно использовать функцию ReleaseSemaphore(), синтаксис которой выглядит следующим образом

BOOLReleaseSemaphore (HANDLEhSemaphore,LONGlReleaseCount, LPLONGlpPreviosCount)

Параметры:

hSemaphore – хэндл освобожденного объекта семафора;

lReleaseCount – число, которое определяет значение, установленное в счетчике ресурсов семафора при его освобождении;

lpPreviosCount – указатель на место хранения предыдущего значения счетчика.

Возвращаемое значение. При успешном выполнении функция возвращает TRUE, в противном случае – возвращается NULL.

Функция ReleaseSemaphore()увеличивает значение счетчика семафора, идентификатор которого передается ей через параметр hSemaphore, на значение, указанное в параметре lReleaseCount.

Заметим, что через параметр lReleaseCount вы можете передавать только положительное значение, большее нуля.

При этом если в результате увеличения новое значение счетчика должно будет превысить максимальное значение, заданное при создании семафора, функция ReleaseSemaphore()возвращает признак ошибки и не изменяет значение счетчика.

Предыдущее значение счетчика, которое было до использования функции ReleaseSemaphore(), записывается в переменную типа LONG. Адрес этой переменной передается функции через параметр lpPreviousCount.

Таким образом, функция используется для решения двух задач:

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

Во-вторых, эта функция может быть использована на этапе инициализации мультизадачного приложения.

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

В программном интерфейсе операционной системы Windows нет функции, специально предназначенной для уменьшения значения счетчика семафора.

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

Таким образом, алгоритм работы с семафорами выглядит следующим образом:

- поток создает или открывает семафор с помощью функций CreateSemaphore() или OpenSemaphore() соответственно;

- поток вызывает функцию WaitForSingleObject() для того, чтобы определить, свободен ли требуемый потоку ресурс. В зависимости от результата, возвращаемого этой функцией, определяются дальнейшие действия;

- при завершении поток вызывает функцию ReleaseSemaphore(), освобождающую семафор.

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

Одной из проблем, которая возникает при использовании семафоров является проблема синхронизации – взаимные блокировки (дедлоки, клинчи, тупики).