Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Использование семафоров



Классическое приложение семафоров относится к использованию их счетчиков как представления числа доступных ресурсов, таких как число сообщений, ожидающих в очереди. Максимум семафора соответствует максимальной длине очереди. Таким обра­зом, производитель поместит в буфер и вызовет функцию 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 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.008 с)...