Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответы_ОСиСП.docx
Скачиваний:
55
Добавлен:
20.04.2019
Размер:
623.57 Кб
Скачать

20. Синхронизация потоков разных процессов. Объекты синхронизации: флаги, семафоры, события, ожидаемые таймеры, именованные и неименованные «трубы» (каналы).

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

Событие (event) — самая простая разновидность объектов ядра. Оно содержит счетчик количества пользователей и две булевы переменные. Одна переменная указывает тип данного объекта-события, а другая — его состояние. События просто уведомляют об окончании какой-либо операции. Объекты-события бывают двух типов: со сбросом вручную (manual-reset events) или с автосбросом (auto-reset events). Первые события позволяют возобновить выполнение сразу нескольких ждущих потоков, а вторые — только одного потока.

Объект ядра «событие» создается функцией CreateEvent, имеющей следующий

прототип:

HANDLE CreateEvent(

LPSECURITY_ATTRIBUTES eventAttributes, // атрибуты доступа

BOOL bManualReset, // тип сброса

BOOL blnitialState, // начальное состояние

LPCTSTR pszName // имя объекта

):

Объекты ядра «семафор» (semaphore) используются для учета ресурсов. Кроме счетчика числа пользователей семафор содержит два 32-битных значения со знаком. Одно из них определяет максимальное количество ресурсов, контролируемых семафором, а другое используется как счетчик текущего числа ресурсов. Объект ядра «семафор» создается вызовом функции CreateSemaphore:

HANDLE CreateSemaphore (

LPSECURITY_ATTRIBUTES semaphoreAttributes. // атрибуты доступа

LONG llnitialCount, // текущее количество доступных ресурсов

LONG IMaximumCount, // максимальное количество ресурсов

LPCTSTR pszName // имя объекта

);

Например, в результате следующего вызова: HANDLE hSem = CreateSemaphore(NULL, 0. 5, "MySemaphore"); будет создан именованный объект-семафор с максимальным числом ресурсов, равным пяти, и изначально нулевым количеством доступных ресурсов.

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

BOOL ReleaseSemaphoreC

HANDLE hSemaphore. // дескриптор семафора

LONG IReleaseCount. // приращение количества доступных ресурсов

LPLONG lpPreviousCount // предыдущее значение счетчика ресурсов

):

Пожалуй, ожидаемые таймеры - самый изощренный объект ядра для синхронизации. Таймеры создаются функцией CreateWaitableTimer и бывают, также как и события, с автосбросом и без него. Затем таймер надо настроить функцией SetWaitableTimer. Таймер переходит в сигнальное состояние, когда истекает его таймаут. Отменить "тиканье" таймера можно функцией CancelWaitableTimer. Примечательно, что можно указать callback функцию при установке таймера. Она будет выполняться, когда срабатывает таймер.

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

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

Работает канал по схеме: первым вошел – первым вышел, то есть, та информация, которая была записана в канал раньше, будет раньше считана. Это, так называемая, процедура FIFO (First In – First Out). Канал рассчитан на определенный объем информации (обычно 4096 байт). Если канал заполнен и никто из него не читает, процесс записи приостанавливается. Если информация из канала считана и в него никто не пишет, приостанавливается процесс чтения.