Объект-мьютекс отличается от остальных объектов ядра тем, что занявшему его потоку передаются права на владение им. Прочие объекты могут быть либо свободны, либо заняты — вот, собственно, и все. А объекты-мьютексы способны еще и запоминать, какому потоку они принадлежат. Если какой-то посторонний поток попытается освободить мьютекс вызовом функции ReleaseMutex, то она, проверив идентификаторы потоков и обнаружив их несовпадение, ничего делать не станет, а просто вернет FALSE.
Если поток, которому принадлежит мьютекс, завершится, не успев его освободить? В таком случае система считает, что произошел отказ от мьютекса, и автоматически переводит его в свободное состояние. Тогда Wait-функция возвращает WAIT_ABANDONED вместо WAIT_OBJECT_0, сигнализируя тем самым, что мьютекс свободен, но освобожден некорректно. Выяснить, что сделал с защищенными данными бывший владелец объекта-мьютекса, увы, невозможно.
Обычно не проверяют возвращаемое значение на WAIT_ABANDONED, потому что такое завершение потоков происходит очень редко.
Объект «событие» не хранит информацию о том, кто его занял.
Переключение состояния объекта осуществляется вызовом функций:
ResetEvent(hEvent); // Перевод в занятое состояние
SetEvent(hEvent); // Перевод в свободное состояние
События бывают двух типов: с «ручным захватом» и «автоматическим захватом».
События с автоматическим захватом переводятся в занятое состояние
функцией WaitForSingleObject(...), не требуя явного вызова ResetEvent().
Для событий с ручным захватом требуется явно вызывать ResetEvent().
Тип и начальное состояние объекта «событие» задаются при его создании:
HANDLE
CreateEvent(
PSECURITY_ATTRIBUTES psa, // Обычно NULL
BOOL ManualReset, // ручнойзахват - авто
BOOL InitialState, // исходно свободен-занят
PCTSTR pszName // Имясобытия
);
Параметр |
Значение |
Смысл |
ManualReset |
true |
с ручным захватом |
false |
с автозахватом |
|
InitialState |
true |
изначально свободно |
false |
изначально занято |
Если имя события == NULL, его можно использовать только в рамках одного процесса.
Функция возвращает дескриптор созданного объекта, который имеет смысл в рамках данного процесса. Потоки других процессов обычно получают свой дескриптор объекта
вызовом функции OpenEventc передачей в параметре pszName имени объекта:
HANDLE OpenEvent( DWORD fdwAccess, BOOL fInherit, PCTSTR pszName);
Функция возвращает дескриптор только в том случае, когда событие уже создано каким-то процессом, в противном случае возвращается NULL.
Ненужный более объект «событие» следует закрыть вызовом CloseHandle(hEvent).
Семафоры
Семафор представляет собой счетчик, который считается свободным, если значение счетчика больше нуля, и занятым при нулевом значении.
Объект ядра «семафор» создается вызовом функции:
HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTE psa,
LONG InitialCount,
LONG MaximumCount,
PCTRTR pszName
);
Параметр MaximumCountопределяет максимальное число потоков, которые могут одновременно пользоваться разделяемым ресурсом.
Параметр InitialCount- счетчик числа потоков, пользующихся ресурсом в данный момент.
Любой процесс может получить свой «процессо-зависимый» дескриптор существующего объекта «семафор», вызвав OpenSemaphore:
HANDLE OpenSemaphore(DWORD fdwAccess, BOOL bInheritHandle, PCTSTR pszName);
где обычно fdwAccess = SEMAPHORE_ALL_ACCESS, bInheritHandle = true.
Функция возвращает дескриптор только в том случае, когда семафор уже создан каким-то процессом, в противном случае возвращается NULL.
Работа с ресурсом, охраняемым семафором, строится так. Создаем объект «семафор»:
long MaximumCount = .... ;
HANDLE hSem = CreateSemaphore(NULL, MaximumCount, MaximumCount,”Sem1”);
Это не опечатка – обычно текущее значение счетчика исходно равно максимально допустимому. При каждом успешном вызове функцииWaitForSingleObject() текущее значение уменьшается на 1.
Другой процесс может получить свой дескриптор:
HANDLE hSemaphor = OpenSemaphore(SEMAPHORE_ALL_ACCESS,true, “Sem1”);
Запрос доступа к охраняемому ресурсу оформляется так:
DWORDTimeOut = 2000;
DWORD Result = WaitForSingleObject(hSem, TimeOut);
if(Result == WAIT_OBJECT_0) // Доступполучен
{
< Операциисресурсом >
ReleaseSemaphore(hSem,1,NULL); // Инкрементсчетчикаресурсов - (я
// освободил)
}
else
{
// Доступ к ресурсу не получен
// Можно делать что-нибудь другое
}
Функция WaitForSingleObjectавтоматически уменьшает значение счетчика семафора на 1, если счетчик ненулевой, или переводит поток в режим ожидания до тех пор, пока другой поток не увеличит значение счетчика семафора вызовом функции ReleaseSemaphore().
Поток увеличивает значение счетчика текущего числа ресурсов, заканчивая работу с ресурсом и вызывая функцию ReleaseSemaphore(...):
BOOLReleaseSemaphore( HANDLEhSem,LONGlReleaseCount,
PLONGplPreviousCount);
Параметр lReleaseCount указывает, на сколько увеличить счетчик текущего числа ресурсов. Это значение должно быть > 0 (обычно 1).
3. ЗАДАНИЕ НА РАБОТУ
В программу, созданную в л.р. № 2, добавить объекты синхронизации, используя их поочередно:
- мьютекс;
- событие.
- семафор.
Оформить подключение синхрообъектов посредством RadioGroup.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.