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; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!