Using Event Objects

< BACK  NEXT >
[oR]

Event kernel objects are used to allow a thread to block until another thread has completed a task. For example, one thread may be reading data from the Internet, and other threads can use an event to block until all the data has been read. Events can either be "manual-reset" or "auto-reset", and the type of event affects how threads blocking on the event behave.

  • Manual-Reset Events: When the event becomes signaled through a thread calling SetEvent, all threads blocking on the event will be unblocked. The event remains signaled until any thread calls ResetEvent at which point the event becomes non-signaled.

  • Auto-Reset Events: When the event becomes signaled through a thread calling SetEvent, only one thread blocking on the event will be unblocked, at which point the event will automatically become non-signaled.

Events are created through a call to CreateEvent (Table 6.5). This function allows both manual-reset and auto-reset events to be created with either a signaled or non-signaled state. Unlike mutex objects, events are not owned by a thread, so any thread can change the signaled state once it has a handle to the event. As with all kernel objects, CloseHandle should be called on the event handle when it is finished with.

Table 6.5. CreateEvent Creates a new event or opens an existing event
CreateEvent
LPSECURITY_ATTRIBUTES lpMutexAttributes Not supported, pass as NULL.
BOOL bManualReset TRUE to create a manual-reset event, or FALSE for an auto-reset event.
BOOL bInitialState TRUE if the event is to be initially signaled, or FALSE if the event is to be initially non-signaled.
LPTSTR lpName String containing name of event, or NULL if an unnamed event is being created. If this parameter is NULL a new event is always created.
HANDLE Return Value Handle to new or existing event, or NULL on failure. GetLastError returns ERROR_ALREADY_EXISTS if an existing mutex was opened.

The only way to change an event's state to signaled is to call SetEvent. This function takes a single argument that is the handle to the event, and returns TRUE on success, or FALSE for failure. Threads don't need to explicitly change an event's state to non-signaled since this happens automatically when the first thread unblocks. Manual events can be set to non-signaled through calling the ResetEvent function. This function takes a single argument that is the handle to the event and returns a Boolean indicating success or failure.

A third function, PulseEvent, is used primarily with manual events. This function sets an event's state to signaled, and then immediately sets it to non-signaled. All threads that are blocked on the event are unblocked. However, any threads that subsequently call WaitForSingleObject will block on the event until either PulseEvent or SetEvent are called.

As an example of when an event may be used, consider the code in Listing 6.3. The function Listing6_3 declares a local variable structure "threadInfo", initializes the structure, and passes a pointer to a new thread through the CreateThread function. The thread function takes a copy of the structure pointed to by lpThreadInfo into a local structure variable called tInfo. Surprisingly, this thread function fails most of the time, since the thread function receives garbage in the structure that is passed to it. This is a classic synchronization problem the function that creates the threads returns and the stack space occupied by the structure is reused when the thread goes on to call other functions. By the time the thread does execute, its pointer refers to a structure that is long gone (Figure 6.5).

Figure 6.5. Problem passing structure pointer to thread function
graphics/06fig05.gif
Listing 6.3 Thread creation that requires an event for synchronization
 typedef struct tagTHREADINFO {     DWORD dwVal1, dwVal2; } THREADINFO, *LPTHREADINFO; DWORD WINAPI ThreadFunc(LPVOID lpThreadInfo); void Listing6_3() {   THREADINFO threadInfo;   HANDLE hThread;   DWORD dwThreadId;   threadInfo.dwVal1 = 20;   threadInfo.dwVal2 = 40;   hThread = CreateThread(NULL, 0, ThreadFunc,         (LPVOID)&threadInfo, 0, &dwThreadId);   CloseHandle(hThread); } DWORD ThreadFunc(LPVOID lpThreadInfo) {   LONG lResult;   THREADINFO tInfo = *((LPTHREADINFO)lpThreadInfo);   lResult = tInfo.dwVal1 * tInfo.dwVal2;   cout   _T("Result: ")   lResult    endl;   return 0; } 

This problem can be fixed by creating a non-signaled event in the function Listing3_4, and having the Listing3_4 function block after creating the thread. The thread function ThreadFunc can then signal the event once it has taken a copy of the structure. This is shown in Listing 6.4, with the lines of code added for synchronization shown in bold. The event has its signal state changed just once with only a single thread waiting on it. Therefore, it does not matter if an auto-reset or manual-reset event is created. Figure 6.6 shows the program flow with this corrected code.

Figure 6.6. Synchronized code for creating thread
graphics/06fig06.gif
Listing 6.4 Thread creation requiring an event for synchronization
 typedef struct tagTHREADINFO {   DWORD dwVal1, dwVal2; }THREADINFO, *LPTHREADINFO; DWORD WINAPI ThreadFunc2(LPVOID lpThreadInfo); HANDLE hEvent; void Listing6_4() {   THREADINFO threadInfo;   HANDLE hThread;   DWORD dwThreadId;   threadInfo.dwVal1 = 20;   threadInfo.dwVal2 = 40;   hEvent = CreateEvent(NULL,       TRUE,   // manual event       FALSE,  // initially non-signaled       NULL);  // no name   hThread = CreateThread(NULL, 0, ThreadFunc2,         (LPVOID)&threadInfo, 0, &dwThreadId);   WaitForSingleObject(hEvent, INFINITE);   CloseHandle(hEvent);   CloseHandle(hThread); } DWORD ThreadFunc2(LPVOID lpThreadInfo) {   LONG lResult;   THREADINFO tInfo = *((LPTHREADINFO)lpThreadInfo);   // Unblock Listing6_4 now the structure has been copied   SetEvent(hEvent);   lResult = tInfo.dwVal1 * tInfo.dwVal2;   cout  _T("Result: ")    lResult    endl;   return 0; } 

Events can be named through the last parameter to CreateEvent. This allows an event to synchronize threads in different processes. Windows CE does not support the OpenEvent function, but CreateEvent can be passed the name of an existing event and it will be opened. GetLastError will return ERROR_ALREADY_EXISTS.


< BACK  NEXT >


Windows CE 3. 0 Application Programming
Windows CE 3.0: Application Programming (Prentice Hall Series on Microsoft Technologies)
ISBN: 0130255920
EAN: 2147483647
Year: 2002
Pages: 181

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net