[win32] How to use WIN32 Event Kernel Object

来源:互联网 发布:淘宝服装批发市场 编辑:程序博客网 时间:2024/06/16 14:05

【自动和手动的Event,例子很好。SM客户端的几个不同线程,有自己的Event。Win32多线程的几种同步方式里,Event是最灵活的方式,因为可以手动设置。】

原文链接:http://www.codeproject.com/Articles/8211/How-to-use-WIN-Event-Kernel-Object


Introduction

Thread synchronization is a problem domain as there are many ways to handle it. There are enough books and articles that show how to avoid multiple threads related nightmare. While working on this nightmare, I come across WIN32 events (WIN32 Kernel objects). Initially, I was unable to understand how to use global kernel objects across threads using global variables; that itself creates hell, but after understanding it, I found it very easy to use. Here, I will explain the usage of WIN32 events in context of Auto and Manual Reset Events.

About WIN32 Events

WIN32 Events are kernel objects and like other kernel objects available across process boundaries. A WIN32 Event works like a state machine and spends its life between two states, i.e., signaled state and non signaled state. An event is in signaled state means that it has the capacity to release the threads waiting for this event to be signaled. An event is in non signaled state means that it will not release any thread that is waiting for this particular event.

Using WIN32 Auto Reset Event

An Auto Reset Event is the event which will guarantee to release a single thread that is waiting on this event to occur and returns back to non signaled state. If more than one thread is waiting for this event to occur then which thread will be released is random.

Creating and using WIN32 Events make use of WIN32 APIs. Some of the APIs are:

CreateEvent(...); // API to Create EventCreateThread(...); // API to Create Thread// API for Waiting for an EventWaitForSingleObject (...); WaitForMultipleObject (...);OpenHandle(...); // API to get Event HandlesSetEvent(...); // API to put an event in signaled state.ResetEvent(...); // API to put an event in non signaled state.CloseHandle(...); // API to close Event Handles

Let's see the code which will use an auto reset event. The scenario is that the main program will create a thread and the thread will wait for an event to get signaled twice. The main program will signal the event and wait for the thread to die.

// Standard include headers#include <windows.h>#include <iostream>using namespace std;DWORD WINAPI Tf ( LPVOID n ){    cout<<"Thread Instantiated........."<<endl;    // Get the handler to the event for which we need to wait in     //    this thread.    HANDLE hEvent = OpenEvent ( EVENT_ALL_ACCESS , false, "MyEvent" );    if ( !hEvent ) { return -1; }    // Loop through and wait for an event to occur    for ( char counter = 0; counter < 2; counter ++ )    {        // Wait for the Event        WaitForSingleObject ( hEvent, INFINITE );        //    No need to Reset the event as its become non signaled as soon as        //    some thread catches the event.        cout<<"Got The signal......."<<endl;    }    CloseHandle(hEvent);    cout<<"End of the Thread......"<<endl;    return 0;}int main(){    //    Create an Auto Reset Event which automatically reset to     //    Non Signalled state after being signalled    HANDLE     hEvent = CreateEvent ( NULL , false , false , "MyEvent" );    if ( !hEvent ) return -1;    //    Create a Thread Which will wait for the events to occur    DWORD Id;    HANDLE hThrd = CreateThread ( NULL, 0, (LPTHREAD_START_ROUTINE)Tf,0,0,&Id );    if ( !hThrd ) { CloseHandle (hEvent); return -1; }    // Wait for a while before continuing....    Sleep ( 1000 );    // Give the signal twice as the thread is waiting for 2 signals to occur    for ( char counter = 0; counter < 2; counter ++ )    {        // Signal the event        SetEvent ( hEvent );        // wait for some time before giving another signal        Sleep ( 2000 );    }    // Wait for the Thread to Die    WaitForSingleObject ( hThrd, INFINITE );        CloseHandle ( hThrd );    CloseHandle ( hEvent );    cout<<"End of Main ........"<<endl;    return 0;}

Code Description

The above code calls CreateEvent ( NULL , false , false , "MyEvent" ); to create an event. The parameter descriptions are given below:

  1. First parameter NULL represents default security attributes.
  2. Second parameter is a flag to Manual reset event. false means the event will be an auto reset event, and manual reset event if the flag is true.
  3. Third parameter is a flag to the state of the event being created. If false the event will be created in non signaled state, and if true the event will be created in signaled state. An event being created in signaled state means that first thread which is waiting for the signal will be released without any call toSetEvent(...); in case of an Auto Reset Event. In case of Manual Reset Event, all threads will be released that are waiting for this signal unless there is a call of ResetEvent(...).
  4. Fourth parameter is the name of the event with which it will be identified globally. If an event with the same name as above already exists then handle to the existing event will open.

The code then creates a thread by calling CreateThread(...) API. We can also use C run time library functionbeginthreadex(...) for creating the thread. The loop runs twice and signals the events after two seconds using SetEvent(...) API. This API takes the handle to the thread.

After signaling the event, the main program waits for the thread to die using WaitForSingleObject(...). The program must close the handle because leaving the handle will have a memory leak.

The thread uses OpenEvent ( EVENT_ALL_ACCESS , false"MyEvent" ); to get the handle to the event. Note that we can access the events only by unique names, so names must be unique. The parameter descriptions are given below:

  1. First parameter allows the thread to wait for this particular event signal.
  2. Second parameter will not allow the events to be inheritable.
  3. Third parameter is the name of the event for which we required a handle.

Using WIN32 Manual Reset Event

An event is called Manual reset event if it has the capacity of releasing as many number of threads which are waiting for this particular event until there is an explicit API call for resetting the event in non signaled state. Creating a manual reset event can be done just by changing the second parameter of the CreateEvent(...);API call. To create a manual reset event, we will call this API as CreateEvent ( NULL , true , false ,"MyEvent" );.

Rest of the program will be similar to that of the auto reset event except that we need to call ResetEvent(...)API. The code is given below:

#include <windows.h>#include <iostream>using namespace std;DWORD WINAPI Tf ( LPVOID n ){    cout<<"Thread Instantiated........."<<endl;    // Get the handler to the event for which we need to wait in     //    this thread.    HANDLE hEvent = OpenEvent ( EVENT_ALL_ACCESS , false, "MyEvent" );    if ( !hEvent ) { return -1; }    // Loop through and wait for an event to occur    for ( char counter = 0; counter < 2; counter ++ )    {        // Wait for the Event        WaitForSingleObject ( hEvent, INFINITE );        // We need to reset the event since the event is manual reset        //    event        ResetEvent ( hEvent );        cout<<"Got The signal......."<<endl;    }    CloseHandle ( hEvent );    cout<<"End of the Thread......"<<endl;    return 0;}int main(){    //    Create an Manual Reset Event where events must be reset     //    manually to non signalled state    HANDLE     hEvent = CreateEvent ( NULL , true , false , "MyEvent" );    if ( !hEvent ) return -1;    //    Create a Thread Which will wait for the events to occur    DWORD Id;    HANDLE hThrd = CreateThread ( NULL, 0, (LPTHREAD_START_ROUTINE)Tf,0,0,&Id );    if ( !hThrd ) { CloseHandle (hEvent); return -1; }    // Wait for a while before continuing....    Sleep ( 1000 );    // Give the signal twice as the thread is waiting for 2 signals to occur    for ( char counter = 0; counter < 2; counter ++ )    {        // Signal the event        SetEvent ( hEvent );        // wait for some time before giving another signal        Sleep ( 2000 );    }    // Wait for the Thread to Die    WaitForSingleObject ( hThrd, INFINITE );        CloseHandle ( hThrd );    CloseHandle ( hEvent );    cout<<"End of Main ........"<<endl;    return 0;}

History

In continuation of this, I will explain the usage and difference between different Event signaling APIs likePulseEvent(...) and SetEvent(...) etc., in my next article.


0 0
原创粉丝点击