Stuck in Control.Invoke

A

Armin Zingler

Hi,

I spend a lot of time to make things thread-safe. This must
be 100% bullet-proof, not only "work in most cases". One issue
is marshalling calls to the UI thread using Control.Invoke
(*not* BeginInvoke in this case). Due to race conditions,
the only reliable way is putting 'Invoke' into a Try-Catch
block. Also, the common way of using 'InvokeRequired' turned
out to be unreliable because it returns False if there's
no handle for the Control.

The problem that I have now is that calling Invoke sometimes
throws an InvalidOperationException if the handle is not
created - which is stil handable - but in some cases it just
does not return. That means, the control handle has been
destroyed and the background thread is stuck in WaitHandle.WaitOne:

mscorlib.dll!System.Threading.WaitHandle.WaitOne
mscorlib.dll!System.Threading.WaitHandle.WaitOne
System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle
System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke
System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke


As to the race conditions mentioned above: You know that
cancelling a thread should be done in a controlled way, not by
calling the thread's 'Abort' method. This is done by setting
a Boolean flag (I call it "CancelRequested") that is checked
repeatedly in the background thread. So, in the control's
OnHandleDestroyed method, the background thread is cancelled
by setting the flag. However, in the background thread, the
flag can be set anywhere between checking the flag and
calling Invoke. The background thread may call Invoke even
while the UI thread is on it's way between the handle being
destroyed and the entry to OnHandleDestroyed (or maybe WndProc),
which is the first chance for me to react on it.

Conclusion: there's no reliable way to avoid the call to Invoke
after the handle has been destroyed.

Now, these facts given, how can I avoid that the background
thread gets stuck in WaitHandle.WaitOne? I'm talking about
a general solution on the Control class level (whereas a Form
has aFormClosing event that notices me of the control being
destroyed in advance).

The only way I currently can think of is a kind of contract
(similar to the Dispose "recommendation") instructing the
user of my control to call a certain, additional method
on my control in the Form's FormClosing handler so that
my control is able to shut down the thread before the
handle will be destroyed. I'm not so enthusiastic about
this solution because the user shouldn't care about the
internals of my Control.

Thanks for reading! Wasn't planned that long. :-/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top