Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответ - Екзаменаційні питання з курсу ОС.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
2 Мб
Скачать
☆

Объект ядра Семафор (semaphore)

Поведение семафора сложнее, чем у других объектов синхронизации. Несмотря на то, что у него нет привязки к контексту потока, как у мьютекса, но зато semaphore обладает внутренним счетчиком. Каждый раз, когда WaitFor***-функция определяет семафор в сигнальном состоянии, этот счетчик уменьшается на единицу. Как только счетчик достигнет нуля, семафор переходит в нейтральное состояние. Создать semaphore можно с помощью API-функции CreateSemaphore.

Описание CreateSemaphore

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

Как видно из прототипа функции, здесь можно задать максимальное число счетчика (параметр LONG lMaximumCount) и сразу инициализировать этот счетчик некоторым числом (LONG lInitialCount). ReleaseSemaphore может увеличить этот счетчик, причем не обязательно на единицу, а на необходимое заданное значение. Объект семафор может использоваться для ограничения числа активных потоков в приложении или для других более сложных задач.

Критические секции

Еще одним синхронизационным примитивом являются critical section. Для работы с ними есть свой набор API, и их нельзя использовать в функциях ожидания WaitFor***. По своим свойствам критические секции очень похожи на мьютексы — в их случае тоже отсутствует угроза взаимоблокировки в контексте одного потока. Перед использованием critical section следует сначала ее инициализировать. Для этого потребуется API-функция InitializeCriticalSection. Единственный параметр, который она принимает — это указатель на объект типа CRITICAL_SECTION (память под этот объект следует выделить заранее). После инициализации с критической секцией можно работать.

Функция EnterCriticalSection переводит объект CRITICAL_SECTION в состояние «занято», после чего ни один другой поток не сможет выполнить код критической секции. LeaveCriticalSection освобождает объект.

Обе API в качестве параметра принимают лишь указатель на инициализированный объект секции, нельзя задать ни время ожидания, ни других дополнительных опций. То есть, функционально, критическая секция является урезанным клоном мьютекса, но в отличие от последнего, работа с ней происходит почти в 100 раз быстрее. Мы теряем в гибкости, зато прибавляем в скорости.

Кстати, насчет времени ожидания функцией EnterCriticalSection я немного соврал. Задать его можно, но только для всех критических секций сразу и только в реестре (ключ HKEY_LOCAL_ MACHINESYSTEMCurrentControlSetControlSession Manager CriticalSectionTimeout). По истечении этого времени WINAPI генерирует исключение EXCEPTION_POSSIBLE_DEADLOCK, которое вполне может означать, что в приложении случилась взаимоблокировка потоков — deadlock. Но об этом чуть позже, пока скажу только, что не стоит эти исключения заворачивать в null.

Помимо EnterCriticalSection есть еще TryEnterCriticalSection, которая не ожидает освобождения объекта критической секции, а просто возвращает FALSE, если потоку не удалось войти в critical section.

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