Problems solving "Cannot access disposed object." exception - c#

In my current project there is a Form class which looks like this:
public partial class FormMain : Form
{
System.Timers.Timer timer;
Point previousLocation;
double distance;
public FormMain()
{
InitializeComponent();
distance = 0;
timer = new System.Timers.Timer(50);
timer.AutoReset = true;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (previousLocation != null)
{
// some code
UpdateDistanceLabel(distance);
UpdateSpeedLabel(v);
}
previousLocation = Cursor.Position;
}
private void UpdateDistanceLabel(double newDistance)
{
if (!lblDistance.IsDisposed && !IsDisposed)
{
Invoke(new Action(() => lblDistance.Text = String.Format("Distance: {0} pixels", newDistance)));
}
}
private void UpdateSpeedLabel(double newSpeed)
{
if (!lblSpeed.IsDisposed && !IsDisposed)
{
Invoke(new Action(() => lblSpeed.Text = String.Format("Speed: {0} pixels per second", newSpeed)));
}
}
}
As you can see, I am using a System.Timers.Timer object. I know I could use System.Windows.Forms.Timer, but I'm fairly interested in the reason why I'm still getting the exception shown in the title. It gets thrown at the Invoke call in the UpdateDistanceLabel method. What confuses me is that it says "Cannot access disposed object: FormMain" even though I am checking whether it is disposed or not. So that shouldn't happen. I have also tried disposing the timer object in the FormClosing event as well as overriding Dispose(bool) and disposing it there, both of which unfortunately didn't help at all. Also, the exception does not always get thrown, supposedly only when the timer happens to fire whilst the program is exiting. It still happens a lot.
I've seen that there are tons of threads about this, but I've already tried the solutions posted there, most of them involve checking the IsDisposed property - which doesn't work for me. So I guess I am doing something wrong.
So my question:
Why does the code posted above fire an exception even though I am checking whether the objects I am accessing are disposed or not?

There are two workarounds: either swallow the exception and curse Microsoft for not having included a TryInvoke and TryBeginInvoke methods, or else use locking to ensure that no attempt is made to Dispose the object while it's in use, and no attempt is made to use the object while Dispose is in progress. I think swallowing the exception is probably better, but some people have a visceral reaction against such things, and using locking it is possible to avoid having the exception occur in the first place.

One problem is that you are doing the check on the timer thread, before calling Invoke. There is a possible race condition, where the Form can be disposed after your check and before the invoked action is executed.
You should be doing the check inside the method (lambda expression in your case) called by Invoke.
Another possible problem is that you're accessing Cursor.Position on the timer thread. I'm not sure if this is valid - I'd do this on the main thread. Your code also includes the comment //some code - so you've presumably omitted some code that you also need to check.
Overall, you'd probably be better using a System.Windows.Forms.Timer.

Here is my solution to your exception if you are interested:
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
timer.Stop();
Application.DoEvents();
}
.Stop() without .DoEvents() is not enough, as it'll dispose objects without waiting for your thread to finish its work.

Create two booleans called 'StopTimer' and 'TimerStopped' with their initial states set to false. Set the timer's AutoReset property to false. Then format the Elapsed method to the following:
Invoke((MethodInvoker)delegate {
// Work to do here.
});
if (!StopTimer)
timer.Start();
else
TimerStopped = true;
This way you are preventing a race condition, checking if the timer should continue and reporting when the method has reached its end.
Now set your FormClosing method to this:
if (!TimerStopped)
{
StopTimer = true;
Thread waiter = new Thread(new ThreadStart(delegate {
while (!TimerStopped) { }
Invoke((MethodInvoker)delegate { Close(); });
}));
waiter.Start();
e.Cancel = true;
}
else
timer.Dispose();
If the timer hasn't stopped yet, a thread is launched to wait until it has done so and then try to close the form again.

Related

How to correctly dispose a Form, without risk of an Invoke being called from another thread on a disposed object?

I have a Form which "listens" to events that are raised elsewhere (not on the Form itself, nor one of its child controls). Events are raised by objects which exist even after the Form is disposed, and may be raised in threads other than the one on which the Form handle was created, meaning I need to do an Invoke in the event handler (to show the change on the form, for example).
In the Dispose(bool) method of the form (overridden) I unsubscribed from all events that may still be subscribed when this method is called. However, Invoke is still called sometimes from one of the event handlers. I assume this is because the event handler gets called just a moment before the event is unsubscribed, then OS switches control to the dispose method which executes, and then returns control back to the handler which calls the Invoke method on a disposed object.
Locking the threads doesn't help because a call to Invoke will lock the calling thread until main thread processes the invoked method. This may never happen, because the main thread itself may be waiting for a release of the lock on the object that the Invoke-calling thread has taken, thus creating a deadlock.
So, in short, how do I correctly dispose of a Form, when it is subscribed to external events, which may be raised in different threads?
Here's how some key methods look at the moment. This approach is suffering the problems I described above, but I'm not sure how to correct them.
This is an event handler handling a change of Data part of the model:
private void updateData()
{
if (model != null && model.Data != null)
{
model.Data.SomeDataChanged -= new MyEventHandler(updateSomeData);
model.Data.SomeDataChanged += new MyEventHandler(updateSomeData);
}
updateSomeData();
}
This is an event handler which must make changes to the view:
private void updateSomeData()
{
if (this.InvokeRequired) this.myInvoke(new MethodInvoker(updateSomeData));
else
{
// do the necessary changes
}
}
And the myInvoke method:
private object myInvoke(Delegate method)
{
object res = null;
lock (lockObject)
{
if (!this.IsDisposed) res = this.Invoke(method);
}
return res;
}
My override of the Dispose(bool) method:
protected override void Dispose(bool disposing)
{
lock (lockObject)
{
if (disposing)
{
if (model != null)
{
if (model.Data != null)
{
model.Data.SomeDataChanged -= new MyEventHandler(updateSomeData);
}
// unsubscribe other events, omitted for brevity
}
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
}
Update (as per Alan's request):
I never explicitly call the Dispose method, I let that be done by the framework. The deadlock has so far only happened when the application is closed. Before I did the locking I sometimes got some exceptions thrown when a form was simply closed.
There are two approaches to consider. One is to have a locking object within the Form, and have the internal calls to Dispose and BeginInvoke calls occur within the lock; since neither Dispose nor BeginInvoke should take very long, code should never have to wait long for the lock.
The other approach is to just declare that because of design mistakes in Control.BeginInvoke/Form.BeginInvoke, those methods will sometimes throw an exception that cannot practically be prevented and should simply be swallowed in cases where it won't really matter whether or not the action occurs on a form which has been disposed anyway.
I'd like to provide a sort of addendum to supercat's answer that may be interesting.
Begin by making a CountdownEvent (we'll call it _invoke_counter) with an initial count of 1. This should be a member variable of the form (or control) itself:
private readonly CountdownEvent _invoke_counter = new CountdownEvent(1);
Wrap each use of Invoke/BeginInvoke as follows:
if(_invoke_counter.TryAddCount())
{
try
{
//code using Invoke/BeginInvoke goes here
}
finally { _invoke_counter.Signal(); }
}
Then in your Dispose you can do:
_invoke_counter.Signal();
_invoke_counter.Wait();
This also allows you to do a few other nice things. The CountdownEvent.Wait() function has an overload with a timeout. Perhaps you only want to wait a certain period of time to let the invoking functions finish before letting them die. You could also do something like Wait(100) in a loop with a DoEvents() to keep things responsive if you expect the Invokes to take a long time to finish. There's a lot of niftyness you can achieve with this method.
This should prevent any weird timing race condition type of issues and it's fairly simple to understand and implement. If anyone sees any glaring problems with this, I'd love to hear about them because I use this method in production software.
IMPORTANT: Make sure that the disposal code is on the Finalizer's thread (which it should be in a "natural" disposal). If you try to manually call the Dispose() method from the UI thread, it will deadlock because it will get stuck on the _invoke_counter.Wait(); and the Invokes won't run, etc.
I had the problem with the Invoke method while multithreading, and I found a solution that works like a charm!
I wanted to create a loop in a task that update a label on a form to do monitoring.
But when I closed the form window, my Invoke threw an exception because my Form is disposed !
Here is the pattern I implemented to resolve this problem:
class yourClass : Form
{
private bool isDisposed = false;
private CancellationTokenSource cts;
private bool stopTaskSignal = false;
public yourClass()
{
InitializeComponent();
this.FormClosing += (s, a) =>
{
cts.Cancel();
isDisposed = true;
if (!stopTaskSignal)
a.Cancel = true;
};
}
private void yourClass_Load(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task.Factory.StartNew(() =>
{
try
{
while (true)
{
if (token.IsCancellationRequested)
{
token.ThrowIfCancellationRequested();
}
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate { methodToInvoke(); });
}
}
}
catch (OperationCanceledException ex)
{
this.Invoke((MethodInvoker)delegate { stopTaskSignalAndDispose(); });
}
}, token);
}
public void stopTaskSignalAndDispose()
{
stopTaskSignal = true;
this.Dispose();
}
public void methodToInvoke()
{
if (isDisposed) return;
label_in_form.Text = "text";
}
}
I execute methodToInvoke() in an invoke to update the label from the form's thread.
When I close the window, the FormClosing event is called. I take this opportunity to cancel the closing of the window (a.Cancel) and to call the Cancel method of the object Task to stop the thread.
I then access the ThrowIfCancellationRequested() method which throws an OperationCanceledException allowing, juste after, to exit the loop and complete the task.
The Invoke method sends a "Window message" in a Queue.
Microsoft says : « For each thread that creates a window, the operating system creates a queue for window messages. »
So I call another method that will now really close the window but this time by using the Invoke method to make sure that this message will be the last of the Queue!
And then I close the window with the Dispose() method.

Updating UI from background thread - how do I know that my GUI is not disposed?

I have a background thread which updates the UI once it's done. I tried to be as safe as I can, so that I don't call GUI which has been Disposed.
void DoInBackground()
{
try
{
string result = ServerSideProcess();
* if (!IsDisposed && !Disposing)
* BeginInvoke(new StringDelegate(UpdateText), result);
}
catch (Exception ex)
{
* if (!IsDisposed && !Disposing)
* BeginInvoke(new VoidDelegate(UpdateFailed));
}
}
void UpdateText(string txt)
{
if (!IsDisposed && !Disposing)
textbox1.Text = txt;
}
void UpdateFailed()
{
if (!IsDisposed && !Disposing)
textbox1.Text = "failed to get data from server";
}
override Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
components.Dispose();
}
base.Dispose(disposing);
}
I think that I'm safe enough inside the GUI methods - Dispose() won't get called while i'm inside UpdateText(string) or UpdateFailed() because they both run in the same thread, so I'm assuming that checking for IsDisposing and later executing is good enough. But how can I know for sure that the parts in (*) won't get a Dispose() inbetween, which will result BeginInvoke get called on a disposing class, and eventually an application crash?
I tested it by adding Thread.Sleep(2000) between the (*) parts, putting breakpoints before and after the Thread.Sleep, and moving out of the control causing it to get Dispose()d before reaching BeginInvoke. the result - my application crashed. how can i know that the runtime won't give me this unfortunate context switching scenario?
It looks like a problem that is fully solved, for free, by the Backgroundworker.
Any reason not to use it?
I'd call that an exceptional condition- use a try/catch around the BeginInvokes to catch and explicitly handle the exception that gets thrown.
The following does not show me any error message when executed:
BackgroundWorker bw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
Shown += Form1_Shown;
}
void Form1_Shown(object sender, EventArgs e)
{
bw.RunWorkerAsync();
Thread.Sleep(1000);
Dispose();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
//This is your second thread.
Thread.Sleep(2000);
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//This runs when the second thread is finished. Update here.
Text = "Done";
}
In some cases, you may be able to achieve clean shutdown by having the Dispose routine for the control acquire a lock, set a flag, and release the lock; your update routine should acquire the lock, do the BeginInvoke if the flag isn't set, and release the lock. The key purpose of the lock is to ensure that once the update routine has decided to call the BeginInvoke, the control won't get disposed until the update happens.
That having been said, in a lot of ways I think it's cleaner to just do the BeginInvoke and swallow the exception that will occur if the control gets disposed from under you. There really should be a TryBeginInvoke which would do a BeginInvoke and return True if the control is alive and otherwise return False, but alas there is not, nor is there any race-free way to create one without either injecting oneself into the control's Dispose process or letting an exception occur and stifling it.

This BackgroundWorker is currently busy and cannot run multiple tasks concurrently

I'm trying to use a Background Worker in a WPF application. The heavy lifting task uses WebClient to download some HTML and parse some info out of it. Ideally I want to do that downloading and parsing without locking the UI and placing the results in the UI once it's done working.
And it works fine, however, if I quickly submit the "download and parse" command, I get the error:
This BackgroundWorker is currently busy and cannot run multiple tasks
concurrently
So I did some Googling and it seems that I can enable the .WorkerSupportsCancellation property of the background worker and just .CancelAsync(). However, this doesn't work as expected (canceling the current download and parse).
I still get the above error.
Here's my code:
//In window constructor.
_backgroundWorker.WorkerSupportsCancellation = true;
_backgroundWorker.DoWork += new DoWorkEventHandler(_backgroundWorker_DoWork);
_backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
//Declared at class level variable.
BackgroundWorker _backgroundWorker = new BackgroundWorker();
//This is the method I call from my UI.
private void LoadHtmlAndParse(string foobar)
{
//Cancel whatever it is you're doing!
_backgroundWorker.CancelAsync();
//And start doing this immediately!
_backgroundWorker.RunWorkerAsync(foobar);
}
POCOClassFoo foo = new POCOClassFoo();
void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//This automagically sets the UI to the data.
Foo.DataContext = foo;
}
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//DOING THE HEAVY LIFTING HERE!
foo = parseanddownloadresult()!
}
Calling CancelAsync will still fire the RunWorkerCompleted event. In this event, you need to make sure that CancelAsync has not been called, by checking e.Cancelled. Until this event fires, you cannot call RunWorkerAsync.
Alternatively, I would recommend you do what Tigran suggested and create a new BackgroundWorker each time.
Further more, I would recommend storing the results of_backgroundWorker_DoWork in e.Result, then retrieve them from the same in _backgroundWorker_RunWorkerCompleted
Maybe something like this
BackgroundWorker _backgroundWorker;
private BackgroundWorker CreateBackgroundWorker()
{
var bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += _backgroundWorker_DoWork;
bw.RunWorkerCompleted += new _backgroundWorker_RunWorkerCompleted;
return bw.
}
private void LoadHtmlAndParse(string foobar)
{
//Cancel whatever it is you're doing!
if (_backgroundWorer != null)
{
_backgroundWorker.CancelAsync();
}
_backgroundWorker = CreateBackgroundWorker();
//And start doing this immediately!
_backgroundWorker.RunWorkerAsync(foobar);
}
//you no longer need this because the value is being stored in e.Result
//POCOClassFoo foo = new POCOClassFoo();
private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
//Error handling goes here.
}
else
{
if (e.Cancelled)
{
//handle cancels here.
}
{
//This automagically sets the UI to the data.
Foo.DataContext = (POCOClassFoo)e.Result;
}
}
private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//DOING THE HEAVY LIFTING HERE!
e.Result = parseanddownloadresult()!
}
The thing is that CancelAsync() does what it climes: cancel in async way. That means that it will not stop immediately, but after some time. That time can never be calculated or predicted, so you have a couple of options:
Wait until this backround worker stops really, by waiting in cycle until IsBusy property of it becomes false
Or, I think, better solution is to start another background worker, considering that request of cancelation was already sent to the first one, so it will be soon or later stop. In this case, you need to know from which background worker data comes, in order to process it or not, cause on start of second the first one will still run and pump the data from WebService.
Hope this helps.
CancelAsync returns before the worker cancels and stops its work. Hence, your RunWorkerAsync call is starting before the worker is ready, and you're getting that error. You'll need to wait for the worker to be ready first.
When I'm not interested in tracking progress of an async operation, I tend to prefer to just slap a lambda at ThreadPool.QueueUserWorkItem instead of instantiating and setting up a background worker that I have to check the state of to be able to reuse in a sane way.
You need to verify before you kicks in.
f( !bw.IsBusy )
bw.RunWorkerAsync();
else
MessageBox.Show("Can't run the bw twice!");
You are calling CancelAsync without waiting for the background worker to actually cancel the work. Also you must have your own logic for cancelling the work. There is a good example on MSDN which shows how to do it. Basically in your parseanddownloadresult() method you need to check the CancellationPending property.

Waiting for a timer elapsed event to complete before application/service closes/stops

Summary:
Within a Windows service & Console Application I am calling a common library that contains a Timer that periodically triggers an action that takes around 30 seconds to complete. This works fine, however...
When a service stop or application exit is called and the timer is in the ElapsedEventHandler I need the service stop/application exit to wait until the event handler has completed.
I have implemented this functionality by having a Boolean InEvent property that is checked when the timer stop method is called.
While this is functional, the question is: Is this the best way to go about doing this? Is there an alternative approach that may serve this purpose better?
The other issue is that I need to avoid the service stop request failing with a "Service failed to respond to stop request"
This is my implementation
public sealed class TimedProcess : IDisposable
{
static TimedProcess singletonInstance;
bool InEvent;
Timer processTimer;
private TimedProcess()
{
}
public static TimedProcess Instance
{
get
{
if (singletonInstance == null)
{
singletonInstance = new TimedProcess();
}
return singletonInstance;
}
}
public void Start(double interval)
{
this.processTimer = new Timer();
this.processTimer.AutoReset = false;
this.processTimer.Interval = interval;
this.processTimer.Elapsed += new ElapsedEventHandler(this.processTimer_Elapsed);
this.processTimer.Enabled = true;
}
public void Stop()
{
if (processTimer != null)
{
while (InEvent)
{
}
processTimer.Stop();
}
}
void processTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
InEvent = true;
// Do something here that takes ~30 seconds
}
catch
{
}
finally
{
InEvent = false;
processTimer.Enabled = true;
}
}
public void Dispose()
{
if (processTimer != null)
{
Stop();
processTimer.Dispose();
}
}
}
And this is how it is called in the service OnStart / console application main:
TimedProcess.Instance.Start(1000);
This is how it is called in service OnStop and application main (pending keypress):
TimedProcess.Instance.Stop();
Probably the easiest and most reliable way is to use a Monitor. Create an object that the main program and the timer callback can access:
private object _timerLock = new object();
Your main program tries to lock that before shutting down:
// wait for timer process to stop
Monitor.Enter(_timerLock);
// do shutdown tasks here
And your timer callback locks it, too:
void processTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!Monitor.TryEnter(_timerLock))
{
// something has the lock. Probably shutting down.
return;
}
try
{
// Do something here that takes ~30 seconds
}
finally
{
Monitor.Exit(_timerLock);
}
}
The main program should never release the lock once it's obtained it.
If you want the main program to go ahead and shut down after some period of time, regardless of whether it's obtained the lock, use Monitor.TryEnter. For example, this will wait 15 seconds.
bool gotLock = Monitor.TryEnter(_timerLock, TimeSpan.FromSeconds(15));
The return value is true if it was able to obtain the lock.
By the way, I strongly suggest that you use System.Threading.Timer rather than System.Timers.Timer. The latter squashes exceptions, which can end up hiding bugs. If an exception occurs in your Elapsed event, it will never escape, meaning that you never know about it. See my blog post for more information.
EDIT
Each callback to the System.Timers.Timer is queued on the ThreadPool. Be aware that the System.Timers.Timer can have a race condition (you can read more about it here.) System.Threading.Timer is a slightly nicer wrapper which I prefer to use due to it's simplicity.
You haven't described enough details to know if your particular application could handle that race condition, so it's hard to tell. But given your code, it is possible that there might be a callback queued up for processTimer_Elapsed after Stop() is called.
For the service timeout issue --
One way to do this is to make a call to the ServiceController method WaitForStatus with a timeout. I've done this in the past and it works reasonably well, although I recall there being some edge cases around waiting for a very long time.
See the MSDN reference. A sample use is described here.
One possible alternative seems to be to not do the actual work in the timer callback itself but to just queue a work item from there on the tread pool to do the work. Then you can go ahead and dispose of the timer - anything currently running on the thread pool will remain operational, and your service can respond to the stop request immediately but the thread pool item (if queued) will still get processed.

Pause and Resume a Thread

I have this code to pause and resume a thread:
public partial class frmMain : Form
{
(...)
ManualResetEvent wait_handle = new ManualResetEvent(true);
(...)
}
private void frmMain_Shown(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(TheLoop));
}
private void TheLoop(object stateinfo)
{
bool hasInfo = true;
while (doLoop)
{
wait_handle.WaitOne();
bool hasLines = GetInfo();
if (hasLines)
{
//Consuming time Operation 1
System.Threading.Thread.Sleep(7000);
if (CurrentLine < line.Count - 1)
CurrentLine++;
else
{
bool hasInfo2 = GetInfo2();
if (hasInfo2)
{
//Consuming time Operation 2
System.Threading.Thread.Sleep(7000);
}
CurrentLine = 0;
}
}
else
System.Threading.Thread.Sleep(40000); //Wait to query again
}
}
private void btnPauseResume_Click(object sender, EventArgs e)
{
if (btnPauseResume.Text == "Pause")
{
btnPauseResume.Text = "Resume";
wait_handle.Reset();
}
else
{
btnPauseResume.Text = "Pause";
wait_handle.Set();
}
}
The code above shows a cycle information, it works find to pause and resume the "first consuming time operation" but doesn't work for the second one, if I press the button to pause the thread in the second consuming time operation, this one continues and when the first one appears again, then it pauses there.
What am I missing here?
Thx
Have you considered using a Background Worker instead since you are using WinForms? It would probably be easier than trying to 'Pause' a thread. You can check the CancellationPending property to see if a user has elected to cancel the operation. The link has a good sample to look at.
I have never seen someone pausing a thread. Create a delegate and event inside the class or method that you are executing on a separate threat. Execute that event whenever you wish to pause your thred.
There is not any reason that I can see that would prevent a second call to WaitOne from working if placed before the 2nd time consuming operation. Since you are using a ManualResetEvent the wait handle's state will persist until either Set or Reset is called. That means if you resume the thread by calling Set then both calls to WaitOne will pass through. Likewise, if you pause the thread by calling Reset then both calls to WaitOne will block. Of course, it will not be possible to predict where the worker thread will pause if there is more than one call to WaitOne.
Got it guys! the thing is where you put the WaitOne(). For instance, if I have a While Loop (like my example) if I put the wait before it, no matter how many times I hit the pause button, it won't stop the thread, it's logic since the loop already began, but if I put it at the end, then it will work.
Appreciated your help.

Categories