How do you close an application when some WaitHandle is in the middle of a call to WaitOne?
Asked Answered
A

4

9

Is there a standard way to close out an application "cleanly" while some WaitHandle objects may be in the state of a current blocking call to WaitOne?

For example, there may be a background thread that is spinning along in a method like this:

while (_request.WaitOne())
{
    try
    {
        _workItem.Invoke();
    }
    finally
    {
        OnWorkCompleted();
    }
}

I see no obvious way to dispose of this thread without calling Thread.Abort (which from what I understand is discouraged). Calling Close on the _request object (an AutoResetEvent), however, will throw an exception.

Currently, the thread that is running this loop has its IsBackground property set to true, and so the application appears to close properly. However, since WaitHandle implements IDisposable, I'm unsure if this is considered kosher or if that object really ought to be disposed before the app exits.

Is this a bad design? If not, how is this scenario typically dealt with?

Argosy answered 21/6, 2010 at 19:11 Comment(0)
S
8

Define an additional WaitHandle called _terminate that will signal a request to terminate the loop and then use WaitHandle.WaitAny instead of WaitHandle.WaitOne.

var handles = { _request, _terminate };
while (WaitHandle.WaitAny(handles) == 0)
{
  try
  {
    _workItem.Invoke();
  }
  finally
  {
    OnCompleteWork();
  }
}
Scoutmaster answered 21/6, 2010 at 19:37 Comment(8)
Totally makes sense. But does this mean that it's not OK to simply have the thread running this loop initialized with IsBackground = true (so that when the app exits, the loop terminates even though the WaitHandle is still waiting)?Argosy
@Dan: That's probably okay too, but this method would allow you to gracefully end the thread without having to shutdown the entire application.Scoutmaster
Hi.I just asked you in another question about this pattern, Is this the pattern for stopping a thread via wait handle ? ( instead of using abort/interrupt) ?Wrongful
@RoyiNamir: More or less...yes. Normally only a single ManualResetEvent would be created and then WaitOne would be called with a timeout parameter to simulate a polling interval in an infinite loop. If WaitOne returns false then then loop keeps spinning. If it returns true (because Set was called to request a shutdown) then the loop stops.Scoutmaster
Brian Thanks , If I may , 1 more question : why do you say ManualResetEvent ? if a single thread is waiting - an AutoResetEvent should be fine and more appropriate to this call (because i have just one thread waiting and i dont want all waiting threads to be signaled). am I right ?Wrongful
@RoyiNamir: Yep, an AutoResetEvent will usually work fine as well. I just always use an MRE for this because a shutdown request is typically always in the "requested" state. If you happen to call WaitOne repeatedly you may want it to keep returning true. An ARE does not retain the signaled state. It goes away after WaitOne returns.Scoutmaster
Brian , According to your answer in this post , When I want to have an option of Stopping a thread ( I want to kill him gracefully) , there are 2 options : 1 to use your answer which says : as long as you don't signal me , im still runninng or I can use a volatile field ( also in infinite loop) and check its flag whether to stop or continue. What do you suggest ? ( if it's too much - I can ask it as a separate question - thanks.).Wrongful
@RoyiNamir: No need to post another question...I would start with a volatile field. If that does not satisfy your needs then try an MRE or ARE.Scoutmaster
A
1

Set the IsBackground property to true... it should automatically close the thread when your app ends.

Alternately, you can interrupt the thread by calling Thread.Interrupt and handle the ThreadInterruptedException. Another idea is to call _request.Set() and make the while loop check a volatile flag to determine if the application is closing or if it should continue:

private volatile bool _running = true;
while(_request.WaitOne() && _running)
{
    //...
}

// somewhere else in the app
_running = false;
_request.Set();
Aurora answered 21/6, 2010 at 19:14 Comment(3)
So you're saying there's no need to call Close on the WaitHandle as long as the thread is a background thread?Argosy
@Dan, it has always exited correctly for me... I'm looking for something in the documentation to back that claim up.Aurora
This is the exact same thing as Thread.Abort(). It is just that the CLR will call it.Evulsion
A
1

When a thread is blocking (regardless of what it's blocking on) you can call Thread.Interrupt() This will cause the exception ThreadInterruptedException (I believe, it might be a little different) You can handle this exception on the thread itself and do any neccesary clean up.

It's worth noting, that the thread will only throw the ThreadInterruptedException when it is blocking, if it's not blocking it won't be thrown until it next tries to block.

This is the "safe" way of ending threads from what I've read on the subject.

also worth noting: If the object implements both IDisposable and a finializer (which it will if it uses unmanaged resources) the GC will call the finalizer which normally calls dispose. Normally this is non-deterministic. However you can pretty much guarantee they will get called on application exit. Only under very special circumstances they wouldn't. (A .net environment termininating exception such as StackOverflowException is thrown)

Alack answered 21/6, 2010 at 19:18 Comment(0)
C
0

I think the operating system will clean up after your process has finished. Because your thread is marked as IsBackground the CLR will end the process and all the threads within, so this is not a problem.

Charwoman answered 21/6, 2010 at 19:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.