Exception when Form object is accessed after being disposed

A

aine_canby

Hi,

The problem is that the line -
this.Invoke(new MyDelegate(Function), args); // this = MainForm
is being called after the line -
terminatePopulate = true;

therefore I get an exception which states that MainForm has been
disposed when this.Invoke is called...

Is there a way to check if MainForm has been disposed. Perhaps theres
a better way of doing what am trying to achieve,

Thanks,

Aine

public class FormMain : Form
{
volatile bool terminatePopulate = false;

void FormMain_Load()
{

myThread = new System.Threading.Thread(MyThread());
myThread.Start();
}

void MyThread()
{

while (!anotherObject.ContinueWaiting)
{

if (!terminatePopulate)
this.Invoke(new MyDelegate(Function), args); // concerned
with control on Main Form
else
return;

Thread.Sleep(100); // Updates a control every 100 ms
}

if (!terminatePopulate)
this.Invoke(new MyOtherDelegate(Function), args);
}

private void OnClosing(object sender, EventArgs ev)
{
terminatePopulate = true;
}

}
 
N

Nicholas Paldino [.NET/C# MVP]

The problem here (aside from the synchronization issues that creep up in
setting terminatePopulate) is that in between the check on the value, the
form can be disposed of, which is causing your error.

Rather, what you should do is check the terminatePopulate value in the
delegate which gets called on the UI thread. This will cause you to not
access the form if the value is set.

Then, you can check the value in the loop on the thread in every
iteration to see if you should exit the thread.

You need to place a lock statement around access to the
terminatePopulate variable, as you need to synchrnoize access between the
threads.
 
O

Olie

I would have thought it would be better to terminate the Thread when
the form is disposed. There is a Disposing event for this I believe.
That way the thread can never be running after the form has been
disposed. It also holds better to the IDisposable interface where the
Dispose function is supposed to clean up all resources used by the
object.

I would also recommend that you look into using events to terminate
the thread correctly. You have no way at the moment of knowing when
the thread terminates and so can end up with a situation where the
object is completely destroyed and usless but the thread is still
running. You should at least have myThread.Join() in the closing
event.
 
W

Willy Denoyette [MVP]

Hi,

The problem is that the line -
this.Invoke(new MyDelegate(Function), args); // this = MainForm
is being called after the line -
terminatePopulate = true;

therefore I get an exception which states that MainForm has been
disposed when this.Invoke is called...

Is there a way to check if MainForm has been disposed. Perhaps theres
a better way of doing what am trying to achieve,

Thanks,

Aine

public class FormMain : Form
{
volatile bool terminatePopulate = false;

void FormMain_Load()
{

myThread = new System.Threading.Thread(MyThread());
myThread.Start();
}

void MyThread()
{

while (!anotherObject.ContinueWaiting)
{

if (!terminatePopulate)
this.Invoke(new MyDelegate(Function), args); // concerned
with control on Main Form
else
return;

Thread.Sleep(100); // Updates a control every 100 ms
}

if (!terminatePopulate)
this.Invoke(new MyOtherDelegate(Function), args);
}

private void OnClosing(object sender, EventArgs ev)
{
terminatePopulate = true;
}

}



Any reason why you are using Invoke instead of BeginInvoke?
Use BeginInvoke and set the flag in the FormClosing event handler.

Willy.
 
O

Olie

BeginInvoke will not change anything as it will just hide the
exception that still gets generated because the form has been
disposed.
 
W

Willy Denoyette [MVP]

Olie said:
BeginInvoke will not change anything as it will just hide the
exception that still gets generated because the form has been
disposed.


Invoke has Synchronous call semantics, that is it waits until the delegated
callback returns, the caller is *assumed* to handle the return value and the
exception thrown by the callback .
BeginInvoke has "fire and forget" semantics, that means that the caller does
not care about whatever the delegate returns. In the OP's scenario, all he
needs is an event that indicates that he can stop updating the UI.
If he would like to get the result of the delegate (which can only be an
exception here), he would have wrapped the UI call in a try\catch block
anyway.
There is no easy way to prevent this race. There is no way to control the
sequence of the messages as stored in the Windows Message Queue. WM_CLOSE
message (queued by SendMessage) are always handled before Posted message (as
used by Invoke/BeginIvoke), that means that the already queued
"ThreadCallBack Messages" will be postponed till after the WM_CLOSE has been
processed and as such after the Control has been disposed. Whenever the
Windows loop picks up the previously queued "ThreadCallBack" message and
starts executing the callback it will get a "ObjectDisposedException"
thrown on him, all you can do here is catch the exception in the delegated
function.

Willy.
 

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