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

Объект ядра Событие

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

Описание CreateEvent

HANDLE WINAPI CreateEvent( __in_opt LPSECURITY_ATTRIBUTES lpEventAttributes, __in BOOL bManualReset, __in BOOL bInitialState, __in_opt LPCTSTR lpName );

События имеют возможность автосброса. Для этого надо установить параметр BOOL bManualReset в значение FALSE. В этом случае при обработке ивента функцией WaitFor*** объект автоматически перейдет в нейтральное состояние. Если же bManualReset == TRUE, то сброс флага осуществляется функцией ResetEvent. События могут быть именованными и не именованными. В первом случае к ивенту можно получить доступ из другого процесса, открыв объект с помощью API OpenEvent. Такие events удобно использовать при межпроцессорной синхронизации. Также событию можно задать начальное состояние с помощью параметра BOOL bInitialState. Если он равен TRUE, то объект будет создан сразу в сигнальном состоянии.

Events в связке с WaitFor***-функциями обеспечивает простой и удобный способ синхронизации потоков.

Объект ядра Мьютекс

Мьютекс (mutex) очень похож на event с автосбросом, но, в отличие от последнего, он имеет привязку к конкретному потоку. Если мьютекс находится в сигнальном состоянии, то считается, что он свободен. Как только какой-либо тред дожидается сигнального состояния mutex с помощью функции WaitFor***, объект сбрасывается в нейтральное состояние и считается захваченным этим потоком.

В отличие от события, мьютекс имеет разные состояния для разных тредов. Так, для потока, который захватил mutex, он выглядит как свободный, и все последующие вызовы WaitFor*** вернут результат, говорящий о том, что объект находится в сигнальном состоянии. Все же другие потоки будут видеть его как захваченный объект, то есть в нейтральном состоянии и WaitFor*** API будут ждать, пока он освободится.

Перевести мьютекс обратно в сигнальное состояние можно с помощью функции ReleaseMutex. Кроме того mutex имеет счетчик ссылок. Это означает, что ReleaseMutex надо вызывать столько же раз, сколько были вызваны WaitFor***.

Если понимание того, чем мьютекс отличается от события до сих пор не пришло, то советую взглянуть на пример ниже.

Пример работы Mutex

HANDLE hMutex; void Func() { ::WaitForSingleObject(hMutex, INFINITE); … ::ReleaseMutex(hMutex); } DWORD WINAPI thread1(LPVOID param) { ::WaitForSingleObject(hMutex, INFINITE); Func(); ::ReleaseMutex(hMutex); } DWORD WINAPI thread2(LPVOID param) { ::WaitForSingleObject(hMutex, INFINITE); ... ::ReleaseMutex(hMutex); } int main(...) { hMutex = ::CreateMutex(NULL, FALSE, NULL); HANDLE hThread1 = ::CreateThread(NULL, 0, thread1, ...); HANDLE hThread2 = ::CreateThread(NULL, 0, thread2, ...); }

В этом коде поток thread1 дважды вызывает WaitForSingleObject для нашего мьютекса. Причем вызовы эти вложены друг в друга, то есть сначала два раза вызывается WaitForSingleObject, а затем — два раза ReleaseMutex.

Оба вызова проходят WaitFor*** проходят гладко, так как для thread1 наш мьютекс находится в сигнальном состоянии, несмотря на автосброс. Но этот автосброс влияет на thread2, который ожидает, пока объект станет свободным.

Если бы мы использовали ивенты, то вызов WaitForSingleObject в функции Func в первом потоке привел бы к его полному зависанию, но благодаря свойству мьютекса привязываться к контексту потока, этого не произошло.