Главная Случайная страница Контакты | Мы поможем в написании вашей работы! | ||
|
Классическое приложение семафоров относится к использованию их счетчиков как представления числа доступных ресурсов, таких как число сообщений, ожидающих в очереди. Максимум семафора соответствует максимальной длине очереди. Таким образом, производитель поместит в буфер и вызовет функцию ReleaseSemaphore, обычно со значением счетчика освобождения 1. Потоки-потребители будут выполнять ожидание для семафора, получая сообщения и уменьшая счетчик семафора.
Другое важное применение описано - семафор используется для ограничения числа рабочих потоков, которые реально выполняются в любой момент, снижая таким образом состязание потоков за ресурсы и в некоторых случаях повышая быстродействие.
Другое возможное применение семафоров для контроля числа потоков, которые необходимо пробудить. Все потоки могут создаваться не в приостановленном состоянии, после чего они немедленно начнут ожидание для семафора, инициализированного нулем. Поток-хозяин, вместо того чтобы продолжать выполнение приостановленных потоков, должен будет просто вызвать функцию ReleaseSemaphore со значением счетчика, которое является числом потоков, после чего начнется работа этих потоков. [kgl].
Основная литература: [1] – 228-246 c.
Контрольные вопросы:
1. Назовите объекты синхронизации потоков.
2 Какие объекты могут быть использованы для межпроцессной синхронизации потоков в отдельных процессах?
[gl] Лекция 5. Тема: Дополнительные методы синхронизации потоков [:]
События
Последний объект ядра для синхронизации — события. Этот объект используется для информирования других потоков о том, что произошло некоторое событие, например стало доступно новое сообщение.
Важная дополнительная возможность, предоставляемая событиями, — освобождение нескольких потоков от совместного ожидания, когда в сигнальное состояние перешел один дескриптор. События делятся на сбрасываемые автоматически и вручную, это свойство события устанавливается при вызове функции CreateEvent.
- Событие, сбрасываемое вручную, может сигнализировать одновременно не
скольким потокам, выполняющим ожидание события.
- События с автоматическим сбросом посылают сигналы единственному потоку,
выполняющему ожидание события, и сбрасываются автоматически.
Событиями используются функции CreateEvent, OpenEvent, SetEvent, ResetEvent и PulseEvent.
HANDLE CreateEvent (LPSECURITY_ATTRIBUTES lpsa,
BOOL fManualReset, BOOL fInitialState, LPCTSTR lpszEventName)
При установленном в значение TRUE параметре fManualReset создается событие с ручным сбросом. Аналогично, если событие первоначально должно находиться в сигнальном состоянии, параметр fInitialState необходимо установить в значение TRUE. Чтобы открыть существующее событие, возможно, из другого процесса, следует воспользоваться функцией OpenEvent.
Для управления событиями используются следующие три функции:
BOOL SetEvent (HANDLE hEvent)
BOOL ResetEvent (HANDLE hEvent;
BOOL PulseEvent (HANDLE hEvent)
Поток может перевести событие в сигнальное состояние, использовав функцию SetEvent. Если событие сбрасывается автоматически, единственный (возможно, из многих) ожидающий поток освобождается, а событие автоматически переводится в несигнальное состояние. Если для данного события не выполняет ожидание ни один из потоков, оно остается в сигнальном состоянии до момента, когда поток начнет ожидание, после чего он немедленно освобождается. Отметим, что тот же результат можно получить, использовав семафор с максимальным значением счетчика 1.
Если же, с другой стороны, событие сбрасывается вручную, оно остается в сигнальном состоянии до тех пор, пока поток не вызовет функцию ResetEvent для данного события. В этот промежуток времени все ожидающие потоки освобождаются и возможно, что поток начнет ожидание и будет освобожден до сброса события.
Функция PulseEvent освобождает все события, выполняющие ожидание для данного события с ручным сбросом, которое затем сбрасывается автоматически. В случае события с автосбросом функция PulseEvent освобождает единственное ожидающее событие, если таковое существует.
Отметим, что функция ResetEvent используется только после того, как событие с ручным сбросом будет переведено в сигнальное состояние функцией SetEvent. Будьте осторожны при использовании функции WaitForMultipleObjects для ожидание всех событий, которые должны перейти в сигнальное состояние. Ожидающий поток будет освобожден, только когда все события одновременно окажутся в сигнальном состоянии, а некоторые из событий могут быть сброшены из сигнального состояния до освобождения ожидающего потока.
Обзор: четыре модели использования событий
Комбинирование устанавливаемых вручную и автоматически событий с функциями SetEvent и PulseEvent дает четыре различных пути использования событий.
Предупреждение: при неверном использовании события могут привести к возникновению состояния гонок, зависаниям и другим незаметным и трудно выявляемым ошибкам. В таблице описаны четыре возможные ситуации.
Событие с автоматическим сбросом похоже на дверь с пружиной, которая ее захлопывает, тогда как событие с ручным сбросом не имеет пружины, и поэтому так и остается открытым. Если продолжить аналогию, то функция PulseEvent открывает дверь и немедленно закрывает ее после того, как один (для автосброса) или все (для сброса вручную) ожидающие потоки пройдут через дверь. Функция SetEvent открывает дверь и оставляет ее открытой.
Резюме по использованию событий
События с автосбросом | События с ручным сбросом | |
Функция SetEvent | Освобождается один поток. Если ни один поток в данный момент не выполняет ожидание для данного события, первый же поток, который начнет ожидание в дальнейшем, будет немедленно освобожден. Событие будет сброшено автоматически | Все потоки, ожидающие в данный момент, освобождаются. Событие остается в сигнальном состоянии до тех пор, пока не будет сброшено каким-то потоком |
Функция PulseEvent | Освобождается один поток, но только в случае, если поток в данный момент выполняет ожидание для данного события | Все ожидающие в данный момент потоки, если такие есть, освобождаются, а событие затем сбрасывается. Если нет ни одного ожидающего потока, событие остается в состоянии сигнала до тех пор, пока поток не начнет ожидание для него |
5.2 Дополнительные сблокированные функции
Далее приведено еще несколько функций, которые позволяют выполнять элементарные операции для сравнения и обмена пар переменных.
Сблокированный обмен записывает одну переменную в другую:
LONG InterlockedExchange (LPLONG Target, LONG Value)
Функция возвращает текущее значение переменной *Target и присваивает ей значение Value. Переменная Target должна выравниваться по словам.
Функция InterlockedExchangeAdd добавляет к первому значению второе.
LONG InterlockedExchangeAdd (PLONG Addend, LONG Increment)
Переменная Increment прибавляется к переменной *Addend, и возвращается исходное значение *Addend. Эта функция позволяет выполнить атомарную операцию увеличения переменной на 2 (или большее число), что невозможно сделать последовательными вызовами функции InterlockedIncrement.
Последняя функция, InterlockedCompareExchange, аналогична функции InterlockedExchange, за исключением того, что обмен возможен только в том случае, если равенство выполняется.
PVOID InterlockedCompareExchange (PVOID *Destination,
PVOID Exchange, PVOID Comparand)
Эта функция выполняет в атомарной операции следующие действия (причина использования типа pvoid для двух последних параметров непонятна):
Temp = *Destination;
if (*Destination == Comparand) *Destination = Exchange;
return Temp;
Одно из применений этой функции — блокировка для реализации критической секции кода. Переменная *Destination является "переменной блокировки", для которой 1 значит "разблокировано", а 0 — "заблокировано". Переменная Exchange должна иметь значение 0, a Comparand — значение 1. Вызвавший функцию поток получает во "владение" критическую секцию, если функция возвращает значение 1. Иначе он должен "заснуть" или "зациклиться" — выполнять бесполезный цикл некоторое время, а затем попробовать снова. Это зацикливание — именно то, что делает функция EnterCriticalSection во время ожидания для объекта CRITICAL_SECTION с ненулевым значением счетчика цикла. [kgl].
Основная литература: [1] – 246- 258 c.
Контрольные вопросы:
1. Виды событий
2. Четыре модели использования событий
3. Назначение сблокированных функций
[gl] Лекция 6. Тема: Управление памятью. Использование виртуальной памяти [:]
Дата публикования: 2015-11-01; Прочитано: 489 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!