Help!!! "Cannot access a disposed object." during this.Invoke

J

Jim H

I have a form that has a bunch of events triggered from worker threads. The
event handlers need to update the gui so if it's a worker thread I call
this.Invoke from inside my Form's event handler code. When I close the app
I get the following exception:

System.ObjectDisposedException was unhandled
Message="Cannot access a disposed object.\r\nObject name: 'MainForm'."
Source="System.Windows.Forms"
ObjectName="MainForm"
StackTrace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller,
Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[]
args)
at SniperScope.MainForm.OnPidDataArrived(Object source,
DataLoggerEventArgs e) in F:\code\Logger VS8
**** more underlying calls in the stack but this is the meat****

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing ); <-- main thread is here when exception occurs
}

The offending code:
public void OnPidDataArrived(object source, DataLoggerEventArgs e)
{
object[] loaArgs = new object[1];
loaArgs[0] = e.PIDResults;
if (this.Disposing == false)
{
//check to see if this is the calling thread
//gui operations should only happen in the calling thread
if (this.InvokeRequired)
this.Invoke(m_UIGaugeDelegate, loaArgs); <-- BOOM!!!!!!
Exception when app is closing
else//this is the thread that owns the control handle
OnUpdateGauges(e.PIDResults);
}
}
m_UIGaugeDelegate is a delegate for the OnUpdateGauges method.
I am checking Disposing in the gui operation call that happens on the main
thread as well (OnUpdateGauges)

The problem appears to be that Disposed is called between the time that
OnPidDataArrived checks the value of Disposing and the call to
this.Invoke(). (Actually each time the debugger comes up after the
exception this.InvokeRequired is false) In the debugger the main thread is
currently executing base.Dispose() from my Dispose() code and the worker is
stopped at this.Invoke().

I can't figure a way around this. If I try to use a lock, or some kind of
thread sync object, in Dispose() and this method it dead locks because the
main thread is blocked on the lock in Dispose waiting for the worker to
release the lock, so the Invoke call never comes back in the worker thread.

I running VS.NET 2005 and .NET2.0 and ported the app over from .NET1.1. The
condition did not seem to happen in .NET1.1 and VS.NET 2003, but it was
mostly run on a single processor laptop. My workstation is a dual Xeon
processor machine. This might be exaggerating the issue. I can duplicate
the problem EVERY single time I try to close the app. I haven't run it on
my notebook. (Something in my code is broken and running a single processor
is not a fix.)

How can I synchronize this? I have been wrestling this for a while. Any
ideas would be greatly appreciated.

Thanks,
jim
 
D

Dave Sexton

Hi Jim,

How about ensuring that the worker threads are stopped before calling base.Dispose?

--
Dave Sexton

Jim H said:
I have a form that has a bunch of events triggered from worker threads. The event handlers need to update the gui so if it's a
worker thread I call this.Invoke from inside my Form's event handler code. When I close the app I get the following exception:

System.ObjectDisposedException was unhandled
Message="Cannot access a disposed object.\r\nObject name: 'MainForm'."
Source="System.Windows.Forms"
ObjectName="MainForm"
StackTrace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at SniperScope.MainForm.OnPidDataArrived(Object source, DataLoggerEventArgs e) in F:\code\Logger VS8
**** more underlying calls in the stack but this is the meat****

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing ); <-- main thread is here when exception occurs
}

The offending code:
public void OnPidDataArrived(object source, DataLoggerEventArgs e)
{
object[] loaArgs = new object[1];
loaArgs[0] = e.PIDResults;
if (this.Disposing == false)
{
//check to see if this is the calling thread
//gui operations should only happen in the calling thread
if (this.InvokeRequired)
this.Invoke(m_UIGaugeDelegate, loaArgs); <-- BOOM!!!!!! Exception when app is closing
else//this is the thread that owns the control handle
OnUpdateGauges(e.PIDResults);
}
}
m_UIGaugeDelegate is a delegate for the OnUpdateGauges method.
I am checking Disposing in the gui operation call that happens on the main thread as well (OnUpdateGauges)

The problem appears to be that Disposed is called between the time that OnPidDataArrived checks the value of Disposing and the
call to this.Invoke(). (Actually each time the debugger comes up after the exception this.InvokeRequired is false) In the
debugger the main thread is currently executing base.Dispose() from my Dispose() code and the worker is stopped at this.Invoke().

I can't figure a way around this. If I try to use a lock, or some kind of thread sync object, in Dispose() and this method it
dead locks because the main thread is blocked on the lock in Dispose waiting for the worker to release the lock, so the Invoke
call never comes back in the worker thread.

I running VS.NET 2005 and .NET2.0 and ported the app over from .NET1.1. The condition did not seem to happen in .NET1.1 and
VS.NET 2003, but it was mostly run on a single processor laptop. My workstation is a dual Xeon processor machine. This might be
exaggerating the issue. I can duplicate the problem EVERY single time I try to close the app. I haven't run it on my notebook.
(Something in my code is broken and running a single processor is not a fix.)

How can I synchronize this? I have been wrestling this for a while. Any ideas would be greatly appreciated.

Thanks,
jim
 
C

Chris R. Timmons

Jim,

Check both Disposing and IsDisposed when calling Invoke:

if (!this.Disposing && !this.IsDisposed)
...

I would also echo Dave Sexton's suggestion of stopping the worker
threads before the form is disposed of. That can be done in the
Dispose method's "if (disposing)" block of code.
 
D

Dave Sexton

Hi Chris,

I'm not sure that checking both properties is going to help synchronization due to multi-threading because it's still possible that
the worker thread will enter the 'if' block when both Disposing and IsDisposed return false but before the worker thread reaches the
call to Invoke the base.Dispose method is called on the UI thread.

If the op wants to ensure that there is no synchronization issue, including deadlocks with the UI thread, he/she should ensure that
the worker threads are no longer executing when tearing down the component, otherwise there is a relationship between the worker
thread code and the UI thread that is, IMO, backwards. If the UI thread creates the worker thread, then the UI thread should
tear-down the worker thread, IMO. It's less reasonable for the worker thread to try to synchronize with the thread by which it was
created, creating a tight coupling between the threads that is less intuitive and harder to manage. Everywhere the op wants to call
Invoke in the worker thread they then must first realize their decision on synchronization (i.e. lock, wait handle, etc.).
 
J

Jim H

Thanks for the reply. How would I do that? I create one worker thread that
reads packets from a device. That worker then calls
ThreadPool.QueueUserWorkItem(m_EventProcessor, lPacket);

The event processor method determines the packet type and fires the
appropriate events. The event handlers are being processed from the default
thread pool because the fireXXXevent happened from a thread in the thread
pool. Not all events require gui operations only some.

Threads in thread pools don't end. I do stop the worker threads I create
with
new Thread(new ThreadStart(this.ReadThread));.

It there a way to know if threads in the pool are busy? Maybe empty the
queue?

jim



Dave Sexton said:
Hi Jim,

How about ensuring that the worker threads are stopped before calling
base.Dispose?

--
Dave Sexton

Jim H said:
I have a form that has a bunch of events triggered from worker threads.
The event handlers need to update the gui so if it's a worker thread I
call this.Invoke from inside my Form's event handler code. When I close
the app I get the following exception:

System.ObjectDisposedException was unhandled
Message="Cannot access a disposed object.\r\nObject name: 'MainForm'."
Source="System.Windows.Forms"
ObjectName="MainForm"
StackTrace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller,
Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[]
args)
at SniperScope.MainForm.OnPidDataArrived(Object source,
DataLoggerEventArgs e) in F:\code\Logger VS8
**** more underlying calls in the stack but this is the meat****

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing ); <-- main thread is here when exception
occurs
}

The offending code:
public void OnPidDataArrived(object source, DataLoggerEventArgs e)
{
object[] loaArgs = new object[1];
loaArgs[0] = e.PIDResults;
if (this.Disposing == false)
{
//check to see if this is the calling thread
//gui operations should only happen in the calling thread
if (this.InvokeRequired)
this.Invoke(m_UIGaugeDelegate, loaArgs); <-- BOOM!!!!!!
Exception when app is closing
else//this is the thread that owns the control handle
OnUpdateGauges(e.PIDResults);
}
}
m_UIGaugeDelegate is a delegate for the OnUpdateGauges method.
I am checking Disposing in the gui operation call that happens on the
main thread as well (OnUpdateGauges)

The problem appears to be that Disposed is called between the time that
OnPidDataArrived checks the value of Disposing and the call to
this.Invoke(). (Actually each time the debugger comes up after the
exception this.InvokeRequired is false) In the debugger the main thread
is currently executing base.Dispose() from my Dispose() code and the
worker is stopped at this.Invoke().

I can't figure a way around this. If I try to use a lock, or some kind
of thread sync object, in Dispose() and this method it dead locks because
the main thread is blocked on the lock in Dispose waiting for the worker
to release the lock, so the Invoke call never comes back in the worker
thread.

I running VS.NET 2005 and .NET2.0 and ported the app over from .NET1.1.
The condition did not seem to happen in .NET1.1 and VS.NET 2003, but it
was mostly run on a single processor laptop. My workstation is a dual
Xeon processor machine. This might be exaggerating the issue. I can
duplicate the problem EVERY single time I try to close the app. I
haven't run it on my notebook. (Something in my code is broken and
running a single processor is not a fix.)

How can I synchronize this? I have been wrestling this for a while. Any
ideas would be greatly appreciated.

Thanks,
jim
 
J

Jim H

Thanks for the reply. Doesn't matter the values change after I check them.
Even the this.InvokeRequired flag changes after the check and before the
Invoke call. (At least in the debugger when I check after the exception is
thrown);
 
D

Dave Sexton

Hi Jim,

I see your dilemma.

If you're not using the 2.0 framework you can keep your existing architecture by wrapping the Invoke method call in a
try...catch(ObjectDisposedException) block. In the catch block you could probably just return immediately to the caller seeing as
the user interface has already been torn down.

If you're using the 2.0 framework I've posted some code that should do the trick. It uses the new SynchronizationContext to marshal
calls to the UI thread, which doesn't depend on the Form class so there won't be any ObjectDisposedException if a ThreadPool Thread
attempts to execute a method on the UI Thread event after the Form is disposed. In the example I forward the SynchronizationContext
along to all of the async methods instead of using a field just in case your architecture is more OO. The only issue with this
solution is that other controls might be disposed as well so if the call does go through to the UI thread you'll still get an
ObjectDisposedException if you attempt to use a child control, but the problem is solved by checking Disposing and IsDisposed before
using any controls. Disposing and IsDisposed must be checked on the UI thread to prevent multi-threading issues (as I've done in my
example).

private void Start()
{
System.Threading.Thread workerThread = new System.Threading.Thread(
new System.Threading.ParameterizedThreadStart(mainThread));

// start the workerThread and pass in the application's current SynchronizationContext
workerThread.Start(System.Threading.SynchronizationContext.Current);
}

// Non-pooled thread
private void mainThread(object state)
{
while (!IsDisposed)
// when the form is disposed the thread will stop executing
{
System.Threading.Thread.Sleep(100);

// execute a thread on the pool (forwarding the state object, which is the SynchronizationContext of the app)
System.Threading.ThreadPool.QueueUserWorkItem(
new System.Threading.WaitCallback(pooled), state);
}
}

// pooled thread
private void pooled(object state)
{
// retrieve the SynchronizationContext of the app
System.Threading.SynchronizationContext syncContext = (System.Threading.SynchronizationContext) state;

// TODO: acquire appropriate event delegate for invocation

// Invoke a method on the UI Thread, asynchronously (Post) or synchronously (Send)
// I'm also using an anonymous method in-line to save some space. If the method
// requires more functionality than what I've provided here you should expand it
// to an external method or object.
syncContext.Post(
(System.Threading.SendOrPostCallback) delegate(object postState)
{
// The following code executes on the UI thread.

if (Disposing || IsDisposed)
// Form and its children cannot be used at this time
return;

// TODO: invoke delegate
}, null);
}

--
Dave Sexton

Jim H said:
Thanks for the reply. How would I do that? I create one worker thread that reads packets from a device. That worker then calls
ThreadPool.QueueUserWorkItem(m_EventProcessor, lPacket);

The event processor method determines the packet type and fires the appropriate events. The event handlers are being processed
from the default thread pool because the fireXXXevent happened from a thread in the thread pool. Not all events require gui
operations only some.

Threads in thread pools don't end. I do stop the worker threads I create with
new Thread(new ThreadStart(this.ReadThread));.

It there a way to know if threads in the pool are busy? Maybe empty the queue?

jim



Dave Sexton said:
Hi Jim,

How about ensuring that the worker threads are stopped before calling base.Dispose?

--
Dave Sexton

Jim H said:
I have a form that has a bunch of events triggered from worker threads. The event handlers need to update the gui so if it's a
worker thread I call this.Invoke from inside my Form's event handler code. When I close the app I get the following exception:

System.ObjectDisposedException was unhandled
Message="Cannot access a disposed object.\r\nObject name: 'MainForm'."
Source="System.Windows.Forms"
ObjectName="MainForm"
StackTrace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at SniperScope.MainForm.OnPidDataArrived(Object source, DataLoggerEventArgs e) in F:\code\Logger VS8
**** more underlying calls in the stack but this is the meat****

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing ); <-- main thread is here when exception occurs
}

The offending code:
public void OnPidDataArrived(object source, DataLoggerEventArgs e)
{
object[] loaArgs = new object[1];
loaArgs[0] = e.PIDResults;
if (this.Disposing == false)
{
//check to see if this is the calling thread
//gui operations should only happen in the calling thread
if (this.InvokeRequired)
this.Invoke(m_UIGaugeDelegate, loaArgs); <-- BOOM!!!!!! Exception when app is closing
else//this is the thread that owns the control handle
OnUpdateGauges(e.PIDResults);
}
}
m_UIGaugeDelegate is a delegate for the OnUpdateGauges method.
I am checking Disposing in the gui operation call that happens on the main thread as well (OnUpdateGauges)

The problem appears to be that Disposed is called between the time that OnPidDataArrived checks the value of Disposing and the
call to this.Invoke(). (Actually each time the debugger comes up after the exception this.InvokeRequired is false) In the
debugger the main thread is currently executing base.Dispose() from my Dispose() code and the worker is stopped at
this.Invoke().

I can't figure a way around this. If I try to use a lock, or some kind of thread sync object, in Dispose() and this method it
dead locks because the main thread is blocked on the lock in Dispose waiting for the worker to release the lock, so the Invoke
call never comes back in the worker thread.

I running VS.NET 2005 and .NET2.0 and ported the app over from .NET1.1. The condition did not seem to happen in .NET1.1 and
VS.NET 2003, but it was mostly run on a single processor laptop. My workstation is a dual Xeon processor machine. This might
be exaggerating the issue. I can duplicate the problem EVERY single time I try to close the app. I haven't run it on my
notebook. (Something in my code is broken and running a single processor is not a fix.)

How can I synchronize this? I have been wrestling this for a while. Any ideas would be greatly appreciated.

Thanks,
jim
 
J

Jim H

Thanks a lot. I'll give that a shot.
jim

Dave Sexton said:
Hi Jim,

I see your dilemma.

If you're not using the 2.0 framework you can keep your existing
architecture by wrapping the Invoke method call in a
try...catch(ObjectDisposedException) block. In the catch block you could
probably just return immediately to the caller seeing as the user
interface has already been torn down.

If you're using the 2.0 framework I've posted some code that should do the
trick. It uses the new SynchronizationContext to marshal calls to the UI
thread, which doesn't depend on the Form class so there won't be any
ObjectDisposedException if a ThreadPool Thread attempts to execute a
method on the UI Thread event after the Form is disposed. In the example
I forward the SynchronizationContext along to all of the async methods
instead of using a field just in case your architecture is more OO. The
only issue with this solution is that other controls might be disposed as
well so if the call does go through to the UI thread you'll still get an
ObjectDisposedException if you attempt to use a child control, but the
problem is solved by checking Disposing and IsDisposed before using any
controls. Disposing and IsDisposed must be checked on the UI thread to
prevent multi-threading issues (as I've done in my example).

private void Start()
{
System.Threading.Thread workerThread = new System.Threading.Thread(
new System.Threading.ParameterizedThreadStart(mainThread));

// start the workerThread and pass in the application's current
SynchronizationContext
workerThread.Start(System.Threading.SynchronizationContext.Current);
}

// Non-pooled thread
private void mainThread(object state)
{
while (!IsDisposed)
// when the form is disposed the thread will stop executing
{
System.Threading.Thread.Sleep(100);

// execute a thread on the pool (forwarding the state object, which
is the SynchronizationContext of the app)
System.Threading.ThreadPool.QueueUserWorkItem(
new System.Threading.WaitCallback(pooled), state);
}
}

// pooled thread
private void pooled(object state)
{
// retrieve the SynchronizationContext of the app
System.Threading.SynchronizationContext syncContext =
(System.Threading.SynchronizationContext) state;

// TODO: acquire appropriate event delegate for invocation

// Invoke a method on the UI Thread, asynchronously (Post) or
synchronously (Send)
// I'm also using an anonymous method in-line to save some space. If
the method
// requires more functionality than what I've provided here you should
expand it
// to an external method or object.
syncContext.Post(
(System.Threading.SendOrPostCallback) delegate(object postState)
{
// The following code executes on the UI thread.

if (Disposing || IsDisposed)
// Form and its children cannot be used at this time
return;

// TODO: invoke delegate
}, null);
}

--
Dave Sexton

Jim H said:
Thanks for the reply. How would I do that? I create one worker thread
that reads packets from a device. That worker then calls
ThreadPool.QueueUserWorkItem(m_EventProcessor, lPacket);

The event processor method determines the packet type and fires the
appropriate events. The event handlers are being processed from the
default thread pool because the fireXXXevent happened from a thread in
the thread pool. Not all events require gui operations only some.

Threads in thread pools don't end. I do stop the worker threads I create
with
new Thread(new ThreadStart(this.ReadThread));.

It there a way to know if threads in the pool are busy? Maybe empty the
queue?

jim



Dave Sexton said:
Hi Jim,

How about ensuring that the worker threads are stopped before calling
base.Dispose?

--
Dave Sexton

I have a form that has a bunch of events triggered from worker threads.
The event handlers need to update the gui so if it's a worker thread I
call this.Invoke from inside my Form's event handler code. When I close
the app I get the following exception:

System.ObjectDisposedException was unhandled
Message="Cannot access a disposed object.\r\nObject name: 'MainForm'."
Source="System.Windows.Forms"
ObjectName="MainForm"
StackTrace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller,
Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[]
args)
at SniperScope.MainForm.OnPidDataArrived(Object source,
DataLoggerEventArgs e) in F:\code\Logger VS8
**** more underlying calls in the stack but this is the meat****

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing ); <-- main thread is here when exception
occurs
}

The offending code:
public void OnPidDataArrived(object source, DataLoggerEventArgs e)
{
object[] loaArgs = new object[1];
loaArgs[0] = e.PIDResults;
if (this.Disposing == false)
{
//check to see if this is the calling thread
//gui operations should only happen in the calling thread
if (this.InvokeRequired)
this.Invoke(m_UIGaugeDelegate, loaArgs); <-- BOOM!!!!!!
Exception when app is closing
else//this is the thread that owns the control handle
OnUpdateGauges(e.PIDResults);
}
}
m_UIGaugeDelegate is a delegate for the OnUpdateGauges method.
I am checking Disposing in the gui operation call that happens on the
main thread as well (OnUpdateGauges)

The problem appears to be that Disposed is called between the time that
OnPidDataArrived checks the value of Disposing and the call to
this.Invoke(). (Actually each time the debugger comes up after the
exception this.InvokeRequired is false) In the debugger the main
thread is currently executing base.Dispose() from my Dispose() code and
the worker is stopped at this.Invoke().

I can't figure a way around this. If I try to use a lock, or some kind
of thread sync object, in Dispose() and this method it dead locks
because the main thread is blocked on the lock in Dispose waiting for
the worker to release the lock, so the Invoke call never comes back in
the worker thread.

I running VS.NET 2005 and .NET2.0 and ported the app over from .NET1.1.
The condition did not seem to happen in .NET1.1 and VS.NET 2003, but it
was mostly run on a single processor laptop. My workstation is a dual
Xeon processor machine. This might be exaggerating the issue. I can
duplicate the problem EVERY single time I try to close the app. I
haven't run it on my notebook. (Something in my code is broken and
running a single processor is not a fix.)

How can I synchronize this? I have been wrestling this for a while.
Any ideas would be greatly appreciated.

Thanks,
jim
 

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