Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
196
Добавлен:
20.02.2016
Размер:
115.2 Кб
Скачать

[11.2.3] Семафоры

Семафоры являются более гибкой формой мьютексов. В отличие от мьютексов, программа имеет контроль над тем, сколько потоков одновременно могут захватывать семафор.

Семафор инициализируется с помощью функции KeInitializeSemaphore()

VOID KeInitializeSemaphore(

IN PKSEMAPHORE Semaphore,

IN LONG Count,

IN LONG Limit);

Count – начальное значение, присвоенное семафору, определяющее число свободных в данный момент ресурсов. Если Count=0, семафор находится в несигнальном состоянии (свободных ресурсов нет), если >0 – в сигнальном.

Limit – максимальное значение, которое может достигать Count (максимальное число свободных ресурсов).

Функция KeReleaseSemaphore() увеличивает счетчик семафора Count на указанное в параметре функции значение, т.е. освобождает указанное число ресурсов. Если при этом значение Count превышает значение Limit, значение Count не изменяется и генерируется исключение STATUS_SEMAPHORE_COUNT_EXCEEDED.

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

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

[11.2.4] События (events)

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

  • События, при переводе которых в сигнальное состояние будет разблокирован только один поток, после чего событие автоматически переходит в несигнальное состояние. Такие события носят название события синхронизации (synchronization events)

  • События, при переводе которых в сигнальное состояние будут разблокированы все ожидающие их потоки. Событие должно быть переведено в несигнальное состояние вручную. Такие события носят название оповещающих (notification event).

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

KeInitializeEvent() – инициализирует событие. Память под событие уже должна быть выделена. При инициализации указывается тип – синхронизация или оповещение, а также начальное состояние – сигнальное или несигнальное. Имя события задать нельзя. Функция может быть использована в случайном контексте памяти на уровне IRQL PASSIVE_LEVEL.

IoCreateNotificationEvent(), IoCreateSynchronizationEvent() – создание нового или открытие существующего события с заданным именем. Если объект с таким именем существует, он открывается, если не существует – то создается. Имя события обычно указывается в директории диспетчера объектов “\BaseNamedObjects”. Именно в этой директории содержатся имена событий, создаваемых или открываемых Win32-функциями CreateEvent()/OpenEvent(). Функция возвращает как указатель на объект-событие, так и его описатель в таблице описателя текущего процесса. Для уничтожения объекта необходимо использовать функцию ZwClose() с описателем в качестве параметра. Описатель должен быть использован в контексте того процесса, в котором он был получен, на уровне IRQL PASSIVE_LEVEL.

KeClearEvent() и KeResetEvent() сбрасывают указанное событие в несигнальное состояние отличие между функциями в том, что KeResetEvent() возвращает состояние события до сброса. Функции могут быть вызваны на уровне IRQL <= DISPATCH_LEVEL.

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

Примечание

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

Следующий код корректно уведомляет все блокированные потоки о наступлении ожидаемого ими события:

KeSetEvent(&DeviceExt->Event, 0, NULL);

KeClearEvent(&DeviceExt->Event);

Соседние файлы в папке Лабы по драйверам