How to safely dispose of a WaitHandle?

291 views Asked by At

Consider this code:

volatile EventWaitHandle waitHandle;

// Thread1, represents an IO-bound worker thread:
while (true) {
  waitHandle?.Set();
}

// Thread 2, represents some "main" thread:
waitHandle = new AutoResetEvent(true);
waitHandle.WaitOne();
Sleep(1000);  // To simulate some work.
// Close the wait handle; we're done with it.
EventWaitHandle handle = waitHandle;
waitHandle = null;
handle?.Close();

The null coalescing operator means that accessing waitHandle is safe from thread1. And the atomicity of setting reference types (plus it's marked volatile) mean that accessing waitHandle after setting it is safe from thread 2. AutoResetEvent (and indeed all classes which inherit from EventWaitHandle) says it's threadsafe. So naively this should all be threadsafe.

However, if thread 1 is inside the Set() method when Thread2 Closes the handle could this lead to undefined behavior/race condition? Looking at the code in the .NET reference implementation I don't see any obvious mechanism that would prevent this.

Close calls Dispose, which calls Close on the SafeWaitHandle, which eventually calls CloseHandle in the WinAPI. Set calls SetEvent in the WinAPI. In both cases I don't see any other obvious threading mechanisms, so it seems possible that I could end up in a situation where one thread is calling CloseHandle on the same handle another is calling SetEvent on. If SetEvent is called first there's no problem but if CloseHandle is called first maybe that would cause problems?

I've tried reading the documentation around CloseHandle and SetEvent but it's still not clear to me.

Is this a potential race condition/undefined behavior or not? If it is a problem, what's the correct way to handle it? I could always wrap calls to Set and Close in a lock but it seems strange to wrap access to a mutex in another synchronization mechanism.

For reference I've found this older question asking essentially the same thing. The guidance there was to not Close the handles after all, but the blog linked is a dead link and leaving IDisposable objects hanging without cleaning up after them leaves a bad taste in my mouth. Is this still the proper way to handle this?

0

There are 0 answers