Wait Functions

[Previous] [Next]

Wait functions cause a thread to voluntarily place itself into a wait state until a specific kernel object becomes signaled. By far the most common of these functions is WaitForSingleObject:

 DWORD WaitForSingleObject( HANDLE hObject, DWORD dwMilliseconds); 

When a thread calls this function, the first parameter, hObject, identifies a kernel object that supports being signaled/nonsignaled. (Any object mentioned in the list in the previous section works just great.) The second parameter, dwMilliseconds, allows the thread to indicate how long it is willing to wait for the object to become signaled.

The following function call tells the system that the calling thread wants to wait until the process identified by the hProcess handle terminates:

 WaitForSingleObject(hProcess, INFINITE); 

The second parameter tells the system that the calling thread is willing to wait forever (an infinite amount of time) until this process terminates.

Usually, INFINITE is passed as the second parameter to WaitForSingleObject, but you can pass any value (in milliseconds). By the way, INFINITE is defined as 0xFFFFFFFF (or -1). Of course, passing INFINITE can be a little dangerous. If the object never becomes signaled, the calling thread never wakes up—it is forever deadlocked but, fortunately, not wasting precious CPU time.

Here's an example of how to call WaitForSingleObject with a timeout value other than INFINITE:

 DWORD dw = WaitForSingleObject(hProcess, 5000); switch (dw) { case WAIT_OBJECT_0: // The process terminated. break; case WAIT_TIMEOUT: // The process did not terminate within 5000 milliseconds. break; case WAIT_FAILED: // Bad call to function (invalid handle?) break; } 

The code above tells the system that the calling thread should not be schedulable until either the specified process has terminated or 5000 milliseconds have expired, whichever comes first. So this call returns in less than 5000 milliseconds if the process terminates, and it returns in about 5000 milliseconds if the process hasn't terminated. Note that you can pass 0 for the dwMilliseconds parameter. If you do this, WaitForSingleObject always returns immediately.

WaitForSingleObject's return value indicates why the calling thread became schedulable again. If the object the thread is waiting on became signaled, the return value is WAIT_OBJECT_0; if the timeout expires, the return value is WAIT_TIMEOUT. If you pass a bad parameter (such as an invalid handle) to WaitForSingleObject, the return value is WAIT_FAILED (call GetLastError for more information).

The function below, WaitForMultipleObjects, is similar to WaitForSingleObject except that it allows the calling thread to check the signaled state of several kernel objects simultaneously:

 DWORD WaitForMultipleObjects( DWORD dwCount, CONST HANDLE* phObjects, BOOL fWaitAll, DWORD dwMilliseconds); 

The dwCount parameter indicates the number of kernel objects you want the function to check. This value must be between 1 and MAXIMUM_WAIT_OBJECTS (defined as 64 in the Windows header files). The phObjects parameter is a pointer to an array of kernel object handles.

You can use WaitForMultipleObjects in two different ways—to allow a thread to enter a wait state until any one of the specified kernel objects becomes signaled, or to allow a thread to wait until all of the specified kernel objects become signaled. The fWaitAll parameter tells the function which way you want it to work. If you pass TRUE for this parameter, the function will not allow the calling thread to execute until all of the objects have become signaled.

The dwMilliseconds parameter works exactly as it does for WaitForSingleObject. If, while waiting, the specified time expires, the function returns anyway. Again, INFINITE is usually passed for this parameter, but you should write your code carefully to avoid the possibility of deadlock.

The WaitForMultipleObjects function's return value tells the caller why it got rescheduled. The possible return values are WAIT_FAILED and WAIT_TIMEOUT, which are self-explanatory. If you pass TRUE for fWaitAll and all of the objects become signaled, the return value is WAIT_OBJECT_0. If you pass FALSE for fWaitAll, the function returns as soon as any of the objects becomes signaled. In this case, you probably want to know which object became signaled. The return value is a value between WAIT_OBJECT_0 and (WAIT_OBJECT_0 + dwCount -1). In other words, if the return value is not WAIT_TIMEOUT and is not WAIT_FAILED, you should subtract WAIT_OBJECT_0 from the return value. The resulting number is an index into the array of handles that you passed as the second parameter to WaitForMultipleObjects. The index tells you which object became signaled.

Here's some sample code to make this clear:

 HANDLE h[3]; h[0] = hProcess1; h[1] = hProcess2; h[2] = hProcess3; DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000); switch (dw) { case WAIT_FAILED: // Bad call to function (invalid handle?) break; case WAIT_TIMEOUT: // None of the objects became signaled within 5000 milliseconds. break; case WAIT_OBJECT_0 + 0: // The process identified by h[0] (hProcess1) terminated. break; case WAIT_OBJECT_0 + 1: // The process identified by h[1] (hProcess2) terminated. break; case WAIT_OBJECT_0 + 2: // The process identified by h[2] (hProcess3) terminated. break; } 

If you pass FALSE for the fWaitAll parameter, WaitForMultipleObjects scans the handle array from index 0 on up, and the first object that is signaled terminates the wait. This can have some undesirable ramifications. For example, your thread might be waiting for three child processes to terminate by passing three process handles to this function. If the process at index 0 in the array terminates, WaitForMultipleObjects returns. Now the thread can do whatever it needs to and then loop back around, waiting for another process to terminate. If the thread passes the same three handles, the function returns immediately with WAIT_OBJECT_0 again. Unless you remove the handles that you've already received notifications from, your code will not work correctly.



Programming Applications for Microsoft Windows
Programming Applications for Microsoft Windows (Microsoft Programming Series)
ISBN: 1572319968
EAN: 2147483647
Year: 1999
Pages: 193

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