I need to do this in order to solve a deadlock.
My Windows Forms Control has a reference to a C++/CLI class which wraps a C++ native class. The native class makes callbacks to the C++/CLI class, which maps them to events handled by the form. These callbacks are called from a thread which runs all the time.
When I want to dispose the control, I unregister all events, so that the native class can’t call back anymore. Once that’s done, I dispose the C++/CLI wrapper, which in turn destroys the native class. In the native class destructor, I signal the thread to end using a Windows event, and wait indefinitely for the thread to end.
However, if the thread was in the middle of a callback when the disposal starts, he might be stopped in a Control.Invoke, and deadlock ensues. Hence the title question. Is this possible? If it were so, I could proceed this way:
- Unregister all events (native thread won’t be able to call back anymore)
- Wait for all pending .Invokes to finish
- Dispose C++/CLI wrapper
- Destroy C++ native class
- Signal thread to end
- Wait for thread to end (can’t deadlock with an
Invokesince all of those finished and no more of them could have been fired since events were unregistered)
- Destroy C++ native class
- Bliss
I’m open to other suggestions for solving this problem
There is no possibility of responding to the form closing event and wait for the thread to finish. There’s an unsolvable threading race condition. And very good odds for deadlock, DoEvents would break it but is too ugly.
Implement the FormClosing event and tell the class to stop running its thread. And cancel the close. The thread should raise an event just before it exits. Use BeginInvoke() in the event handler to marshal that call to the main thread.
Now you have a guarantee that all invokes are completed since they are ordered. Furthermore, you have a guarantee that the thread can no longer generate any more events so no more invokes are coming and it is safe to unsubscribe the events (not actually necessary). Set a flag that a real close is now possible and call Close() to actually close the form.