Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
АОПИ. Старое / АОПИ. Глава 2. Конспекты (02_04_19).rtf
Скачиваний:
65
Добавлен:
10.09.2019
Размер:
363.46 Кб
Скачать

Функция создания семафора

HANDLE CreateSemaphore(

IN LPSECURITY_ATTRIBUTES lpSemAttr,

IN LONG lInitCount,

IN LONG lMaxCount,

IN LPCSTR lpName

);

(1) lpSemAttr определяет указатель на структуру SECURITY_ATTRIBUTES. Если этот параметр равен NULL, дескриптор не может наследоваться дочерними процессами. Член этой структуры lpSecurityDescriptor определяет дескриптор безопасности для нового семафора. Если lpSemAttr имеет значение NULL, семафор получает дескриптор безопасности по умолчанию.

(2) lInitCount определяет начальное значение счетчика.

(3) lMaxCount определяет максимальное значение счетчика.

(4) lpName определяет имя семафора.

Возвращаемое значение:

Если функция завершается успешно, возвращаемое значение является дескриптором объекта семафора.

Если указанный объект семафора существовал до вызова функции, функция возвращает дескриптор существующего объекта, а параметры 2 и 3 игнорируются.

Если функция завершается ошибкой, возвращаемое значение равно NULL.

Функция открытия семафора

HANDLE OpenSemaphore(

IN DWORD dwDesiredAccess,

IN BOOL bInheritHandle,

IN LPCSTR lpName

);

Параметры и описание:

(1) dwDesiredAccess — определяет доступ к объекту. 3 варианта: SEMAPHORE_ALL_ACCESS (позволяет выполнять все действия по отношению к объекту семафора), SEMAPHORE_MODIFY_STATE (поток может использовать только функцию ReleaseSemaphore), SYNCHRONIZE (в потоке можно использовать события функций ожидания).

(2) bInheritHandle — определяет наследование. TRUE — дочерние процессы наследуют дескриптор. FALSE — не наследуют.

(3) lpName — определяет имя семафора.

Возвращаемое значение:

Если функция завершилась успешно, она возвращает дескриптор объекта семафора, в противном случае — возвращает NULL.

Функция увеличения счетчика семафора на указанное количество

BOOL ReleaseSemaphore(

IN HANDLE hSemaphore,

IN LONG lReleaseCount,

OUT LPLONG lpPrevCount

);

Параметры и описание:

(1) hSemaphore определяет дескриптор объекта семафора.

(2) lReleaseCount определяет величину, на которую увеличивается текущее число объектов семафора. Значение должно быть больше нуля.

(3) lpPrevCount определяет указатель на переменную для записи в неё предыдущего значения счетчика семафора. Можно указать NULL.

Возвращаемое значение:

Если функция завершается успешно, возвращаемое значение отлично от нуля (bool: true), иначе возвращаемое значение равно 0 (bool: false).

Пример.

/// S — handle семафора

long N = MaxCount;

if (ReleaseSemaphore(S, 1, &N))

WaitForSingleObject(S, 1000);

Если текущее значение счетчика меньше максимально возможного, то вызов функции ReleaseSemaphore сохраняет в N текущее значение счетчика, увеличивает счетчик на 1 и возвращает TRUE. Последующий вызов функции WaitForSingleObject уменьшает значение счетчика на 1, т. е. возвращает его к исходному состоянию.

Если текущее значение равно максимальному, то эта функция вернет FALSE и в N останется исходное значение.

Пример.

HANDLE S = CreateSemaphore(NULL, MaxCount, MaxCount, "Sem1");

// Клиент ресурса, если он находится в другом потоке, соединяется с семафором:

HANDLE S = OpenSemaphore(SEMAPHORE_ALL_ACCESS, true, "Sem1");

DWORD Result = WaitForSingleObject(S, 2000);

if (Result == WAIT_OBJECT_0) {

// действия с ресурсами

// освобождение ресурса:

ReleaseSemaphore(S, 1, NULL);

}

else {

// отсутствие доступа к ресурсу

}

Пример (C).

В следующем примере объект-семафор используется для ограничения числа потоков, которые могут выполнять определенную задачу. Сначала он использует функцию CreateSemaphore для создания семафора и указания начального и максимального количества, затем он использует функцию CreateThread для создания потоков.

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

Когда поток завершает задачу, он использует функцию ReleaseSemaphore для увеличения счетчика семафора, что позволяет другому ожидающему потоку выполнить задачу.

#include <stdio.h>

#include <locale.h>

#include <windows.h>

#define MAX_SEM_COUNT 10 /// Счетчик семафора

#define THREADCOUNT 51 /// Количество потоков

HANDLE ghSemaphore;

DWORD WINAPI ThreadProc(LPVOID);

int main() {

setlocale(LC_ALL, "Russian");

HANDLE aThread[THREADCOUNT]; /// Дескрипторы

DWORD ThreadID;

int i;

/// Создаем семафор

ghSemaphore = CreateSemaphore(NULL, MAX_SEM_COUNT, MAX_SEM_COUNT, NULL);

if (ghSemaphore == NULL) { /// Если ошибка

printf("CreateThread ошибка: %d\n", GetLastError());

return 1;

}

/// Создаем работающие потоки

for (i = 0; i < THREADCOUNT; i++) {

aThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThreadProc, NULL, 0, &ThreadID);

if (aThread[i] == NULL) { /// Если ошибка

printf("CreateThread ошибка: %d\n", GetLastError());

return 1;

}

}

/// Ждем все потоки INFINITE-time

WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);

/// Закрываем дескрипторы потоков

for (i = 0; i < THREADCOUNT; i++)

CloseHandle(aThread[i]);

CloseHandle(ghSemaphore); /// и семафора

return 0;

}

/// Функция потоков

DWORD WINAPI ThreadProc(LPVOID lpParam) {

DWORD dwWaitResult;

BOOL bContinue = TRUE;

while (bContinue) {

/// Попробуем войти в семафор

dwWaitResult = WaitForSingleObject(ghSemaphore, 0L);

/// При 0L будут возникать случаи "время истекло"

/// При INFINITE везде будет "успешное выполнение"

switch (dwWaitResult) {

/// Объект семафора в сигнальном состоянии

case WAIT_OBJECT_0:

/// Выполняем задачу

printf("Поток %d: успешное выполнение\n", GetCurrentThreadId());

/// Остановка цикла while

bContinue = FALSE;

/// Имитация работы потока (он спит)

Sleep(5);

/// Выпуск семафора после завершения задачи