Подія (Windows)

Подія (об'єкт події, event object) в операційній системі Windows — об'єкт для синхронізації виконання процесів (потоків), який може знаходитися у двох станах (сигнальному та несигнальному)[1].

Застосунки (прикладні програми) можуть використовувати об'єкти подій у різних ситуаціях, щоб повідомити потік про виникнення потрібної події. В загальному випадку, об’єкти подій використовують для сигналізації очікуючим потокам про досягнення певних умов виконання програми.

Види об'єктів подій

[ред. | ред. код]

Бувають події ручного скидання (manual-reset) та автоматичного скидання (auto-reset). Подія ручного скидання, будучи сигнальною, залишається такою, доки не буде вимкнена програмно викликом функції API ResetEvent. Події автоматичного скидання перемикаються у несигнальний стан системою, коли один із очікуючих потоків закінчить роботу[1].

Робота з подіями

[ред. | ред. код]

Для створення події використовується функція API CreateEvent. Її опис мовою C++:[2]:

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

Опис мовою Delphi[3]:

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++[4]:

HANDLE WINAPI OpenEvent(  __in  DWORD dwDesiredAccess,  __in  BOOL bInheritHandle,  __in  LPCTSTR lpName ); 

Опис мовою Delphi[3]:

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[3].

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).

Джерела

[ред. | ред. код]
  1. а б MSDN: Event Objects [Архівовано 15 жовтня 2012 у Wayback Machine.].
  2. MSDN: CreateEvent function [Архівовано 22 червня 2012 у Wayback Machine.].
  3. а б в Коноваленко І.В., Федорів П.С. Системне програмування у Windows з прикладами на Delphi, Т:ТНТУ.- 2012 [Архівовано 8 грудня 2012 у Wayback Machine.].
  4. MSDN: OpenEventfunction [Архівовано 18 квітня 2012 у Wayback Machine.].

Дивись також

[ред. | ред. код]