Подія (об'єкт події, event object) в операційній системі Windows — об'єкт для синхронізації виконання процесів (потоків), який може знаходитися у двох станах (сигнальному та несигнальному)MSDN: Event Objects ..
Застосунки (прикладні програми) можуть використовувати об'єкти подій у різних ситуаціях, щоб повідомити потік про виникнення потрібної події. В загальному випадку, об’єкти подій використовують для сигналізації очікуючим потокам про досягнення певних умов виконання програми.
Види об'єктів подій Бувають події ручного скидання (manual-reset) та автоматичного скидання (auto-reset). Подія ручного скидання, будучи сигнальною, залишається такою, доки не буде вимкнена програмно викликом функції API ResetEvent. Події автоматичного скидання перемикаються у несигнальний стан системою, коли один із очікуючих потоків закінчить роботу.
Робота з подіями Для створення події використовується функція API CreateEvent. Її опис мовою C++:MSDN: CreateEvent function .: HANDLE WINAPI CreateEvent( __in_opt LPSECURITY_ATTRIBUTES lpEventAttributes, __in BOOL bManualReset, __in BOOL bInitialState, __in_opt LPCTSTR lpName ); Опис мовою DelphiКоноваленко І.В., Федорів П.С. Системне програмування у Windows з прикладами на Delphi, Т:ТНТУ.- 2012 .: function CreateEvent( lpEventAttributes: PSecurityAttributes; // Атрибути секретності bManualReset, // Задає вид події: ручна (true) чи автоматична (false) bInitialState: BOOL; // Задає початк. стан. Якщо true - сигнальний lpName: PChar // Назва (або nil, якщо не потрібно) ): THandle; Функція повертає дескриптор створеного об’єкта або нуль у випадку невдачі. Якщо об’єкт події із заданою назвою вже існує, то повертається його дескриптор. При цьому ігноруються параметри bManualReset та bInitialState, а функція GetLastError поверне значення ERROR_ALREADY_EXISTS. Ім’я події не повинно збігатися з іменами існуючих об’єктів типу Semaphore, Mutex, Job, Waitable Timer або File Mapping. Якщо відомо, що подія вже існує, її дескриптор можна отримати функцією OpenEvent. Опис на C++MSDN: OpenEventfunction .: HANDLE WINAPI OpenEvent( __in DWORD dwDesiredAccess, __in BOOL bInheritHandle, __in LPCTSTR lpName ); Опис мовою Delphi: function OpenEvent( dwDesiredAccess: DWORD; // Задає права доступу до об'єкта bInheritHandle: BOOL; // Вказує, чи може об'єкт успадковуватися // дочірніми процесами lpName: PChar // Ім'я об'єкта ): THandle; Функція повертає дескриптор об'єкта або нуль у випадку помилки. Параметр dwDesiredAccess може набувати одне з таких значень: EVENT_ALL_ACCESS – програма отримує повний доступ до об'єкта; EVENT_MODIFY_STATE – програма може змінювати стан об'єкта функціями SetEvent і ResetEvent; SYNCHRONIZE – можна використовувати об'єкт події у функціях синхронізації. Після отримання дескриптора події його можна використовувати. Для цього Windows API надає такі функції: SetEvent, ResetEvent та PulseEvent. Функція SetEvent встановлює об'єкт у сигнальний стан: BOOL WINAPI SetEvent(__in HANDLE hEvent); // Опис мовою C++ function SetEvent(hEvent: THandle): BOOL; // Опис мовою Delphi Функція ResetEvent скидає об'єкт, встановлюючи його в несигнальний стан: BOOL WINAPI ResetEvent(__in HANDLE hEvent); // Опис мовою C++ function ResetEvent(hEvent: THandle): BOOL; // Опис мовою Delphi Функція PulseEvent встановлює об'єкт у сигнальний стан, дозволяє відпрацювати всім функціям синхронізації, які його очікують, а потім знову скидає об’єкт події. BOOL WINAPI PulseEvent(__in HANDLE hEvent); // Опис мовою C++ function PulseEvent(hEvent: THandle): BOOL; // Опис мовою Delphi
Приклад використання об'єкта події Вказаний приклад демонструє, як за допомогою системного об’єкта події програма може отримувати повідомлення про зміни у певному підрозділі (текст програми мовою Delphi) реєстру Windows. function ThreadFunc(Ptr: Pointer): LongInt; var evnt : THandle; RK : HKey; S : string; begin evnt := CreateEvent(nil, false, false, nil); RegOpenKeyEx(HKEY_CURRENT_USER, 'Software\IC\RegDemo', 0, KEY_READ, RK); RegNotifyChangeKeyValue(RK, true, REG_NOTIFY_CHANGE_LAST_SET, evnt, true); if WaitForSingleObject(evnt, INFINITE) = WAIT_OBJECT_0 then begin S := TimeToStr(Time) + ': У реєстр внесено зміни!'; MessageBox(hWindow, PWideChar(S), 'Ооо!', MB_ICONINFORMATION); end; RegCloseKey(RK); CloseHandle(evnt); end; Спочатку викликом функції CreateEvent створюється об'єкт події автоматичного скидання, дескриптор якого зберігається у змінній evnt. Після цього відкривається потрібна гілка реєстру та за допомогою функції RegNotifyChangeKeyValue здійснюється підписка на отримання повідомлень про зміни у реєстрі. Таким чином RegNotifyChangeKeyValue пов'язує зміни у реєстрі з об’єктом події evnt. Після цього за допомогою функції WaitForSingleObject здійснюється нескінченне очікування на перехід об’єкта evnt у сигнальний стан.
Якщо у вказану гілку реєстру (Software\IC\RegDemo) внесено зміни, то наш потік отримає відповідний сигнал, і програма видасть відповідне повідомлення (за допомогою функції MessageBox).
Джерела
Дивись також Багатонитевість Нить Синхронізація процесів Критична секція М'ютекс Ф'ютекс, швидкий користувацький м'ютекс