In part of the system I am working on I have a background task (started with
a call to BeginInvoke() on a delegate), which at some point needs to read a
property from one of the controls on a form.
Normally this all works great. The problem I am having is if the user closes
the form whilst the background task is running. Execution blocks
indefinitely on the call to Control.Invoke() and the method I supply to it
never begins. The application's message queue doesn't seem busy and the UI
is still responsive other than I have this thread sitting in the background,
stuck on this call. I am calling Invoke() on a custom UserControl that has
not yet been disposed.
The stack trace to where it is blocking inside Invoke() shows up as the
following...
[In a sleep, wait, or join]
mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool
exitContext) + 0x2e bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout,
bool exitContext) + 0x23 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle
waitHandle = {System.Threading.ManualResetEvent}) + 0xa1 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control
caller, System.Delegate method, object[] args, bool synchronous) + 0x36d
bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate
method, object[] args) + 0x48 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate
method) + 0x7 bytes
I can get around the problem by replacing the Invoke() call with a
BeginInvoke() and therefore being able to specify a timeout, but I'm curious
as to why it's happening in the first place.
Thanks
Dave
Peter Duniho - 06 Jul 2007 17:27 GMT
> [...]
> Normally this all works great. The problem I am having is if the user
[quoted text clipped - 3 lines]
> it
> never begins.
If the control is no longer part of the active UI, then I would not expect
the fact that it's not yet disposed to be of much importantance. It is
still not surprising that a control no longer part of the active UI does
not receive any more window messages, which are needed for the Invoke() to
succeed.
The solution is obviously to not try to interact with the control once
it's no longer part of the active UI. How best to do this will depend on
your own code, but it seems you are knee-deep in synchronization issues
anyway, so it should not be hard to figure out.
Pete
Dave Parker - 09 Jul 2007 09:40 GMT
Thanks, this is what I ended up with...
TimeSpan tsTimeout = TimeSpan.FromSeconds(45);
TimeSpan tsPollFreq = TimeSpan.FromMilliseconds(200);
DateTime dtTimeoutTime = DateTime.Now.Add(tsTimeout);
IAsyncResult asyncResult = ui.BeginInvoke(method);
while (!asyncResult.IsCompleted)
{
asyncResult.AsyncWaitHandle.WaitOne(tsPollFreq, false);
if(ui.IsDisposed || ui.Disposing)
throw new ObjectDisposedException("The invocation target has been disposed
or is in the process of being disposed.");
if(DateTime.Now>dtTimeoutTime)
throw new TimeoutException("An invocation on the user interface timed out
after 45 seconds.");
}
>> [...]
>> Normally this all works great. The problem I am having is if the user
[quoted text clipped - 16 lines]
>
> Pete
Developer - 20 May 2008 11:16 GMT
Thanks you,
I had the same problem when clsoing a from and another thread was trying to invoke on it. It got stuck indefinetly.
Your solution works
From http://www.developmentnow.com/g/6_2007_7_0_0_991931/Control-Invoke-blocking-fore
ver-if-form-closed-whilst-background-task-running.ht