Semaphore (семафор)
Семафор представляет собой счетчик, содержащий целое число в диапазоне от 0 до заданной при его создании максимальной величины. Счетчик уменьшается каждый раз, когда поток успешно завершает функцию ожидания, использующую семафор и увеличивается вызовом функции ReleaseSemaphore. При достижении семафором значения 0 он переходит в несигнальное состояние, при любых других значениях счетчика – его состояние сигнальное. Такое поведение позволяет использовать семафор в качестве ограничителя доступа к ресурсу, поддерживающему заранее заданное количество подключений.
Для создания семафора служит функция:
function CreateSemaphore(
lpSemaphoreAttributes: PSecurityAttributes; // Адрес структуры
// TSecurityAttributes
lInitialCount, // Начальное значение счетчика
lMaximumCount: Longint; // Максимальное значение счетчика
lpName: PChar // Имя объекта
): THandle; stdcall;
Функция возвращает идентификатор созданного семафора, либо 0, если создать объект не удалось.
Параметр lMaximumCount задает максимальное значение счетчика семафора, lInitialCount задает начальное значение счетчика и должен быть в диапазоне от 0 до lMaximumCount. lpName задает имя семафора. Если в системе уже есть семафор с таким именем, то новый не создается, а возвращается идентификатор существующего семафора. В случае если семафор используется внутри одного процесса, можно создать его без имени, передав в качестве lpName значение NIL. Имя семафора не должно совпадать с именем уже существующего объекта типов event, mutex, waitable timer, job, или file-mapping.
Идентификатор ранее созданного семафора может быть, также, получен функцией:
function OpenSemaphore(
dwDesiredAccess: DWORD; // Задает права доступа к объекту
bInheritHandle: BOOL; // Задает, может ли объект наследоваться
// дочерними процессами
lpName: PChar // Имя объекта
): THandle; stdcall;
Параметр dwDesiredAccess может принимать одно из следующих значений:
SEMAPHORE_ALL_ACCESS Поток получает все права на семафор
SEMAPHORE_MODIFY_STATE Поток может увеличивать счетчик семафора функцией ReleaseSemaphore
SYNCHRONIZE Только Windows NT – поток может использовать семафор в функциях ожидания
Для увеличения счетчика семафора используется функция:
function ReleaseSemaphore(
hSemaphore: THandle; // Идентификатор семафора
lReleaseCount: Longint; // Счетчик будет увеличен на эту величину
lpPreviousCount: Pointer // Адрес 32-битной переменной,
// принимающей предыдущее значение
// счетчика
): BOOL; stdcall;
Если значение счетчика после выполнения функции превысит заданный для него функцией CreateSemaphore максимум, то ReleaseSemaphore возвращает FALSE и значение семафора не изменяется. В качестве параметра lpPreviousCount можно передать NIL, если это значение нам не нужно.
Рассмотрим пример приложения, запускающего на выполнение несколько заданий в отдельных потоках (например, программа для фоновой загрузки файлов из Internet). Если количество одновременно выполняющихся заданий будет слишком велико, то это приведет к неоправданной загрузке канала. Поэтому реализуем потоки, в которых будет выполняться задание таким образом, чтобы при превышении их количества заранее заданной величины поток останавливался и ожидал завершения работы ранее запущенных заданий.
Code: |
unit LimitedThread;
interface
uses Classes;
type TLimitedThread = class(TThread) procedure Execute; override; end;
implementation
uses Windows;
const MAX_THREAD_COUNT = 10;
var Semaphore: THandle;
procedure TLimitedThread.Execute; begin // Уменьшаем счетчик семафора. Если к этому моменту уже запущено // MAX_THREAD_COUNT потоков – счетчик равен 0 и семафор в // несигнальном состоянии. Поток будет заморожен до завершения // одного из запущенных ранее. WaitForSingleObject(Semaphore, INFINITE);
// Здесь располагается код, отвечающий за функциональность потока, // например загрузка файла ...
// Поток завершил работу, увеличиваем счетчик семафора и позволяем // начать обработку другим потокам. ReleaseSemaphore(Semaphore, 1, NIL); end;
initialization // Создаем семафор при старте программы Semaphore := CreateSemaphore(NIL, MAX_THREAD_COUNT, MAX_THREAD_COUNT, NIL);
finalization // Уничтожаем семафор по завершении программы CloseHandle(Semaphore); end; |
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!