S etEvent ( 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”);
Запрос доступа к охраняемому ресурсу оформляется так:
DWORD TimeOut = 2000;
DWORD Result = WaitForSingleObject(hSem, TimeOut);
if(Result == WAIT_OBJECT_0) // Доступ получен
{
< Операции с ресурсом >
ReleaseSemaphore ( hSem ,1, NULL ); // Инкремент счетчика ресурсов - (я
Освободил)
}
Else
{
Доступ к ресурсу не получен
Можно делать что-нибудь другое
}
Функция WaitForSingleObject автоматически уменьшает значение счетчика семафора на 1, если счетчик ненулевой, или переводит поток в режим ожидания до тех пор, пока другой поток не увеличит значение счетчика семафора вызовом функции ReleaseSemaphore().
Поток увеличивает значение счетчика текущего числа ресурсов, заканчивая работу с ресурсом и вызывая функцию ReleaseSemaphore(...):
BOOL ReleaseSemaphore( HANDLE hSem,LONG lReleaseCount,
PLONG plPreviousCount);
Параметр l ReleaseCount указывает, на сколько увеличить счетчик текущего числа ресурсов. Это значение должно быть > 0 (обычно 1).
|
|
Задание на работу
1. Разработать Windows-приложение, содержащее два вторичных потока.
- В приложении создать глобальную целочисленную переменную.
- Один вторичный поток прибавляет к этой переменной некоторую константу, а затем ее же вычитает. Другой вторичный поток делает противоположные действия – вычитает из этой переменной ту же константу, а затем ее прибавляет.
- Указанные действия каждый поток выполняет в цикле заданное число раз (например, 50). После каждого прохождения тела цикла поток выводит на экран текущее значение глобальной переменной (в Memo). Пример операторов тела цикла (С++Builder):
GlobalData = GlobalData + 3;
Sleep(1);
GlobalData = GlobalData - 3 ;
i = GlobalData;
Form1->Memo1->Lines->Add(IntToStr(i));
Пояснение.Поскольку время выполнения подобного цикла мало, для моделирования асинхронного доступа двух потоков к разделяемому ресурсу (глобальной переменной) в тело цикла добавлен оператор Sleep(1), означающий отказ от остатка кванта времени.
- Обработчик кнопки ПУСК содержит вызовы функции создания вторичных потоков.
|
|
2. Добавить различные объекты синхронизации доступа к разделяемому ресурсу (глобальной переменной), используя их поочередно:
- без синхронизации
- критическая секция
- мьютекс
- событие
- семафор
Оформить подключение синхрообъектов посредством RadioGroup.
3. Провести моделирование и доказать что синхронизация доступа работает
Дата добавления: 2019-07-15; просмотров: 171; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!