Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Защищенный мьютексом участок кода.






ProcessCommonData();

VERIFY(:: ReleaseMutex(g_hMutex));

}

Чем же мьютекс лучше события с автосбросом? В приведенном примере его также можно было бы использовать, только ReleaseMutex надо было бы заменить на SetEvent. Однако может возникнуть следующая сложность. Чаще всего работать с общими данными приходится в нескольких местах. Что будет, если ProcessCommonData в нашем примере вызовет функцию, которая работает с этими же данными и в которой уже есть своя пара WaitFor - ReleaseMutex (на практике это встречается весьма часто)? Если бы мы использовали событие, программа, очевидно, зависла бы, поскольку внутри защищенного блока событие находится в нейтральном состоянии. Мьютекс же устроен более хитро. Для потока-хозяина он всегда остается в сигнализирующем состоянии, несмотря на то, что для всех остальных потоков он при этом находится в нейтральном. Поэтому если поток захватил мьютекс, повторный вызов WaitFor функции не приведет к блокировке. Более того, в мьютекс встроен еще и счетчик, так что ReleaseMutex должна быть вызвана столько же раз, сколько было вызовов WaitFor. Таким образом, мы можем смело защищать каждый участок кода, работающий с общими данными, парой WaitFor - ReleaseMutex, не волнуясь о том, что этот код может быть вызван рекурсивно. Это делает мьютекс очень простым в использовании инструментом.

Семафор (semaphore)

Еще более специфический объект синхронизации. Семафор предназначен для того, чтобы ограничить максимальное число потоков, одновременно работающих с неким ресурсом. По сути, семафор – это событие со счетчиком. Пока этот счетчик больше нуля, семафор находится в сигнализирующем состоянии. Однако каждый вызов WaitFor уменьшает этот счетчик на единицу до тех пор, пока он не станет равным нулю и семафор перейдет в нейтральное состояние. Подобно мьютексу, для семафора есть функция ReleaseSemaphor, увеличивающая счётчик. Однако в отличие от мьютекса семафор не привязан к потоку и повторный вызов WaitFor/ReleaseSemaphor еще раз уменьшит/увеличит счетчик.

классические семафоры-счетчики, используют следующие примитивы.

· sema p () Уменьшает значение семафора (с возможным блокированием потока)

· sema v () Увеличивает значение семафора (с возможным деблокированием ожидающего потока)

· sema tryp () Уменьшает значение семафора (если не требуется блокирование). Примитив sema__tryp () обеспечивает программисту возможность использовать на уровне пользовательских потоков технологию пережидания занятости.

Как можно использовать семафор? Например, с его помощью можно искусственно ограничить многопоточность. Слишком много одновременно активных потоков может заметно ухудшить производительность всей системы из-за частых переключений контекстов. И если уж нам пришлось создать слишком много рабочих потоков, можно ограничить число одновременно активных потоков числом порядка числа процессоров.

Поток создает семафор с помощью функции CreateSemaphore():

HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName);

Первый параметр функции является указателем на структуру SECURITY_ATTRIBUTES. Эта структура содержит информацию о защите создаваемого объекта. Обычно в качестве этого параметра передается NULL и в этом случае создается объект с защитой по умолчанию.
Параметр lInitiаlСоunt содержит начальное значение счетчика семафора.
Параметр lMaximumCount указывает максимально возможное значение счетчика.
Параметр lpName является указателем на строку, в которой содержится имя данного семафора.
После того как семафор успешно создан, поток может обратиться к ресурсу, защищенному семафором, с помощью одной из wait-функций. При этом wait-функции передается дескриптор семафора. После завершения работы с ресурсом поток увеличивает значение счетчика с помощью функции ReleaseSemaphore():

BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount);

Первый параметр функции - дескриптор семафора. Второй параметр указывает величину, на которую должно быть увеличено значение счетчика. Параметр lpPreviousCount является указателем на переменную, в которой функция сохраняет предыдущее значение счетчика. Если сохранять это значение не нужно, то в качестве последнего параметра передается NULL.

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

Когда объект синхронизации вам больше не требуется, не забывайте вызвать функцию CloseHandle. На самом деле, она не обязательно сразу же удалит объект. Дело в том, что хэндлов у объекта может быть создано несколько, тогда он будет удален только когда будет закрыт последний из них.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.