Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to kill WaitForSingleObject(handle, INFINITE)?

I am having problems closing an application that uses WaitForSingleObject() with an INFINITE timout.

The full picture is this. I am doing the following to allow my application to handle the device wakeup event:

Register the event with:

CeRunAppAtEvent("\\\\.\\Notifications\\NamedEvents\\WakeupEvent",
    NOTIFICATION_EVENT_WAKEUP);

Start a new thread to wait on:

Thread waitForWakeThread = new Thread(new ThreadStart(WaitForWakeup));
waitForWakeThread.Start();

Then do the following in the target method:

private void WaitForWakeup()
{
    IntPtr handle = CreateEvent(IntPtr.Zero, 0, 0, "WakeupEvent");
    while (true)
    {
        WaitForSingleObject(handle, INFINITE);
        MessageBox.Show("Wakey wakey");
    }
}

This all works fine until I try to close the application when, predictably, WaitForSingleObject continues to wait and does not allow the app to close properly. We only allow one instance of our app to run at a time and we check for this on startup. It appears to continue running until the device is soft reset.

Is there a way to kill the handle that WaitForSingleObject is waiting for, to force it to return?

Many thanks.

like image 473
Chris Wallis Avatar asked May 17 '11 15:05

Chris Wallis


2 Answers

Use WaitForMultipleObject instead, and pass 2 handles. The existing one, and one for an event called something like 'exit'. During app shutdown, SetEvent on the exit event, and the WaitForMultipleObject will return and you can get it to exit the thread gracefully.

You need to switch on the return value of WaitForMultipleObject to do the appropriate behaviour depending on which one of the handles was triggered.

Possibly, also, you can set the thread to be a background thread. This will prevent it from stopping your application from shutting down when the main thread terminates.

See:

http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx

like image 71
Scott Langham Avatar answered Nov 15 '22 22:11

Scott Langham


This is what I would do...

  1. Use the EventWaitHandle class instead of calling CreateEvent directly. There shouldn't be any need to use the Windows API other than CeRunAppAtEvent (and API calls make code ugly...). Get this working first.
  2. Before creating the thread, create a ManualResetEvent variable that is not initially flagged. Call it "TerminateEvent".
  3. Replace the WaitForSingleObject API call with WaitHandle.WaitAny(WaitHandle[]) and pass an array containing "TerminateEvent" and the EventWaitHandle class wrapping the CeRunAppAtEvent notification.
  4. Your loop can use the return value of WaitAny to determine what to do. The return value is the array index of the wait handle that unblocked the thread, so you can determine whether to continue the loop or not.
  5. To cleanly end the thread, you can call "Set" on your "TerminateEvent" and then "Join" the thread to wait for it to terminate.
like image 32
James Johnston Avatar answered Nov 15 '22 22:11

James Johnston