Типы объектов синхронизации
Список объектов синхронизации включает следующие типы объектов:
· процессы;
· нити;
· события (в узком смысле);
· мьютексы (двоичные семафоры);
· семафоры (недвоичные);
· таймеры;
· уведомления об изменениях в каталоге;
· консольный ввод.
Рассмотрение объектов синхронизации проще всего начать с процессов и нитей. Для тех и других сигнальным состоянием является только состояние завершения работы. Другими словами, можно заставить нить одного процесса ожидать завершения работы другой нити или процесса.
Простейшим из объектов, предназначенных только для синхронизации, является событие (event). Он создается при помощи функции CreateEvent, которая требует указать вид события (с автосбросом или с ручным сбросом), а также его начальное состояние – сигнальное или несигнальное. Переход в сигнальное состояние выполняется функцией SetEvent, а в несигнальное – ResetEvent. Функция PulseEvent как бы совмещает обе предыдущие: сигнальное состояние включается, функция ожидания, если она была вызвана ранее, завершается, но сигнальное состояние тут же сбрасывается.
Событие с автосбросом означает, что функция ожидания при завершении ожидания сбрасывает то событие (или события), которого (которых) она дождалась. Если несколько нитей ждут одного и того же события с автосбросом, то разблокирована будет только одна из них (Windows не гарантирует, какая именно), поскольку остальным «события не достанется». Напротив, событие с ручным сбросом остается в сигнальном состоянии и может быть сброшено только функцией ResetEvent, а до тех пор оно может «накормить» сколько угодно ожидающих нитей. Можно сказать, что событие с ручным сбросом больше похоже не на событие, а на состояние.
Следующий тип объектов – мьютекс (mutex). Это почти в чистом виде двоичный семафор в смысле Дейкстры. Мьютекс может быть либо свободен (это его сигнальное состояние), либо захвачен какой-либо нитью. При создании мьютекса в функции CreateMutex указывается его начальное состояние. Допускается многократный захват мьютекса одной и той же нитью, но после этого нить должна столько же раз освободить мьютекс, чтобы он вернулся в свободное состояние.
Для освобождения мьютекса нить, владеющая им, вызывает функцию ReleaseMutex, которая является аналогом дейкстровской V(S). Никакая другая нить, кроме владельца, не может освободить «чужой» мьютекс.
В специальной функции для захвата мьютекса нет необходимости, поскольку работу примитива P(S) с успехом выполняют функции ожидания.
Если нить, владеющая мьютексом, завершает свою работу, не освободив мьютекс, то он переходит в «заброшенное» состояние: теперь уже никто не может его освободить. Такую ситуацию следует считать признаком неаккуратного программирования, и она может быть признаком наличия в программе более серьезных ошибок синхронизации.
Объект типа семафор (semaphore) представляет собой недвоичный семафор, используемый обычно для управления распределением ограниченного числа единиц ресурса. В функции CreateSemaphore указываются два числа: максимальное значение счетчика, связанного с семафором (сколько всего имеется единиц ресурса), и начальное значение этого счетчика (сколько единиц свободно). Сигнальным является состояние семафора со счетчиком больше нуля. Функция ожидания уменьшает счетчик на 1, а функция ReleaseSemaphore увеличивает его на заданное количество единиц, но так, чтобы результат не превышал максимального значения.
В отличие от мьютекса, семафор не имеет владельца, т.е. возможна и вполне обычна ситуация, когда одна нить захватывает единицы ресурса, а другая освобождает их.
Таймер «для ожидания» (waitable timer) создается с помощью функции CreateWaitableTimer, после чего должен еще быть установлен функцией SetWaitableTimer. При создании таймера указывается его вид: с ручным сбросом или с автосбросом, аналогично объекту «событие». При вызове SetWaitableTimer указывается время до перехода в сигнальное состояние, в единицах по 100 нс. Время можно указать либо абсолютно (когда «зазвонить»), либо относительно текущего момента (как долго ждать). Можно также указать период (в миллисекундах), через который должен повторяться сигнал.
Таймер с ручным сбросом, перейдя в сигнальное состояние, остается в нем до вызова функции CancelWaitableTimer или повторного вызова SetWaitableTimer. Таймер с автосбросом может быть также сброшен функциями ожидания.
Полезно напомнить, что в Windows широко используется и другой тип таймеров «для сообщений», создаваемый функцией SetTimer, но эти таймеры не могут взаимодействовать с функциями ожидания и даже не являются объектами.
Объект типа уведомление об изменениях создается при помощи функции FindFirstChangeNotification. При этом указываются следующие аргументы:
· каталог файловой системы, изменения в котором должны отслеживаться;
· флаг, указывающий, должны ли отслеживаться изменения только в заданном каталоге или также во всех вложенных подкаталогах;
· фильтр отслеживаемых изменений.
Фильтр изменений представляет собой маску, в которой отдельные биты задают такие события, как изменение списка имен файлов и каталогов (это включает их создание, удаление и переименование), изменение атрибутов файла, размера, даты изменения и атрибутов защиты.
Функция возвращает хэндл объекта, который переходит в сигнальное состояние один раз, при первом появлении одного из включенных в фильтр изменений. Если требуется повторять отслеживание, следует вызывать функцию FindNextChangeNotification, передавая ей хэндл. Для удаления объекта нужно вызвать функцию с диким именем FindCloseChangeNotification.
Уведомления об изменениях позволяют избежать активного ожидания для программ, которые должны отслеживать и отображать состояние каталогов в динамике (как это делают, например, Проводник или Far Manager). При этом характер происшедшего изменения программа может выяснить, только перечитав каталог, но зато достоверно известно, что какое-то изменение было.
Хэндл объекта типа консольный ввод возвращается функцией CreateFile, у которой вместо имени открываемого файла указано устройство консольного ввода (CONIN$). Объект в сигнальном состоянии, когда в буфере ввода есть непрочитанные символы.
Дата добавления: 2015-09-07; просмотров: 668;