Why do the pending expectations in ManualResetEvent continue even when Close () is called?

We were surprised to learn today that threads waiting on ManualResetEvent continue to wait for an event even after it closes. We expected the Close() call to implicitly signal pending threads.

We tracked this because some of our Windows services did not close as quickly as we would like. We change all of our Dispose implementations, which first close the ManualResetEvent links to call Set .

Can someone explain why Close does not indirectly call Set ? When do you want the waiting thread to keep waiting?

Here is our test code to demonstrate our results:

  private static readonly Stopwatch _timer = Stopwatch.StartNew(); public static void Test() { var sync = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem(state => { Log("ThreadPool enter, waiting 250ms..."); sync.WaitOne(250); Log("ThreadPool exit"); }); Log("Main sleeping 100"); Thread.Sleep(100); Log("Main about to close"); // sync.Set(); // Is Set called implicitly? No... sync.Close(); Log("Main waiting for exit 500ms"); Thread.Sleep(500); } private static void Log(string text) { Console.WriteLine("{0:0} {1}", _timer.ElapsedMilliseconds, text); } 

When we run this code with the comment Set , we get this.

 0 Main sleeping 100 0 ThreadPool enter, waiting 250ms... 103 Main about to close 103 Main waiting for exit 500ms 259 ThreadPool exit 

When we explicitly call Set , we get this.

 0 Main sleeping 100 0 ThreadPool enter, waiting 250ms... 98 Main about to close 98 ThreadPool exit 98 Main waiting for exit 500ms 
+6
multithreading c # dispose
source share
2 answers

Close - means of utilization of the object ( Close and Dispose in this class gives identical behavior). This does not affect the state of the handle. Suppose in all cases the user needs a thread waiting on a handle that I closed to continue, does not seem reasonable. In fact, the fact that the handle is used should indicate that you should not call Close in the first place.

This is not a question of “why should not Set be called implicitly?”, It is a conceptual problem: if you call Close , you should no longer care about this object. Use Set and Reset to control the flow of threads; do not click Close (or Dispose ) on any object; WaitHandle turned on until they are no longer used.

+2
source share

These synchronization events are based on Win32 wait descriptors, and the Close() method releases them (for example, Dispose() ) without signaling, and waiting threads wait.

+1
source share

All Articles