Avoid calling Invoke when the control is disposed - c#

I have the following code in my worker thread (ImageListView below is derived from Control):
if (mImageListView != null &&
mImageListView.IsHandleCreated &&
!mImageListView.IsDisposed)
{
if (mImageListView.InvokeRequired)
mImageListView.Invoke(
new RefreshDelegateInternal(mImageListView.RefreshInternal));
else
mImageListView.RefreshInternal();
}
However, I get an ObjectDisposedException sometimes with the Invoke method above. It appears that the control can be disposed between the time I check IsDisposed and I call Invoke. How can I avoid that?

What you have here is a race condition. You're better off just catching the ObjectDisposed exception and be done with it. In fact, I think in this case it is the only working solution.
try
{
if (mImageListView.InvokeRequired)
mImageListView.Invoke(new YourDelegate(thisMethod));
else
mImageListView.RefreshInternal();
}
catch (ObjectDisposedException ex)
{
// Do something clever
}

There are implicit race conditions in your code. The control can be disposed between your IsDisposed test and the InvokeRequired test. There's another one between InvokeRequired and Invoke(). You can't fix this without ensuring the control outlives the life of the thread. Given that your thread is generating data for a list view, it ought to stop running before the list view disappears.
Do so by setting e.Cancel in the FormClosing event and signaling the thread to stop with a ManualResetEvent. When the thread completes, call Form.Close() again. Using BackgroundWorker makes it easy to implement the thread completion logic, find sample code in this post.

The reality is that with Invoke and friends, you can't completely protect against invoke on a disposed component, or then getting InvalidOperationException because of the missing handle. I haven't really seen an answer yet, like the one farther below, in any of the threads that addresses the real fundamental problem, which cant be completely solved by preemptive testing or using lock semantics.
Here's the normal 'correct' idiom:
// the event handler. in this case preped for cross thread calls
void OnEventMyUpdate(object sender, MyUpdateEventArgs e)
{
if (!this.IsHandleCreated) return; // ignore events if we arn't ready, and for
// invoke if cant listen to msg queue anyway
if (InvokeRequired)
Invoke(new MyUpdateCallback(this.MyUpdate), e.MyData);
else
this.MyUpdate(e.MyData);
}
// the update function
void MyUpdate(Object myData)
{
...
}
The fundemental problem:
In using the Invoke facility the windows message queue is used, which places a message in the queue to either wait or fire-and-forget the cross thread call exactly like Post or Send message. If there is a message ahead of the Invoke message that will invalidate the component and its window handle, or that got placed just after any checks you try to perform, then you are going to have a bad time.
x thread -> PostMessage(WM_CLOSE); // put 'WM_CLOSE' in queue
y thread -> this.IsHandleCreated // yes we have a valid handle
y thread -> this.Invoke(); // put 'Invoke' in queue
ui thread -> this.Destroy(); // Close processed, handle gone
y thread -> throw Invalid....() // 'Send' comes back, thrown on calling thread y
There is no real way to know that the control is about to remove itself fromthe queue, and nothing really reasonable you can do to "undo" the invoke. No matter how many checks you do or extra locks you make, you cant stop someone else form issuing something like a close, or deactivate. There are tons of senarios where this can happen.
A solution:
The first thing to realize is that the invoke is going to fail, no different than how a (IsHandleCreated) check would have ignored the event. If the goal is to protect the caller on the non-UI thread you will need to handle the exception, and treat it like any other call that didn't succeed (to keep app from crashing or do whatever. And unless going to rewrite/reroll Invoke facility, the catch is your only way to know.
// the event handler. in this case preped for cross thread calls
void OnEventMyWhatever(object sender, MyUpdateEventArgs e)
{
if (!this.IsHandleCreated) return;
if (InvokeRequired)
{
try
{
Invoke(new MyUpdateCallback(this.MyUpdate), e.MyData);
}
catch (InvalidOperationException ex) // pump died before we were processed
{
if (this.IsHandleCreated) throw; // not the droids we are looking for
}
}
else
{
this.MyUpdate(e.MyData);
}
}
// the update function
void MyUpdate(Object myData)
{
...
}
The exception filtering can be tailored to suit whatever the needs are. Its good to be aware that worker threads often dont have all the cushy outer exception handling and logging the UI threads do, in most applicaitons, so you may wish to just gobble up any exception on the worker side. Or log and rethrow all of them. For many, uncaught exceptions on worker thread means the app is going to crash.

Try using
if(!myControl.Disposing)
; // invoke here
I had the exact same problem as you. Ever since I switched to checking .Disposing on the control, the ObjectDisposedException has gone away. Not saying this will fix it 100% of the time, just 99% ;) There is still a chance of a race condition between the check to Disposing and the call to invoke, but in the testing I've done I haven't ran into it (I use the ThreadPool and a worker thread).
Here's what I use before each call to invoke:
private bool IsControlValid(Control myControl)
{
if (myControl == null) return false;
if (myControl.IsDisposed) return false;
if (myControl.Disposing) return false;
if (!myControl.IsHandleCreated) return false;
if (AbortThread) return false; // the signal to the thread to stop processing
return true;
}

may be lock(mImageListView){...} ?

You could use mutexes.
Somewhere at the start of the thread :
Mutex m=new Mutex();
Then :
if (mImageListView != null &&
mImageListView.IsHandleCreated &&
!mImageListView.IsDisposed)
{
m.WaitOne();
if (mImageListView.InvokeRequired)
mImageListView.Invoke(
new RefreshDelegateInternal(mImageListView.RefreshInternal));
else
mImageListView.RefreshInternal();
m.ReleaseMutex();
}
And whereever it is you are disposing of mImageListView :
m.WaitOne();
mImageListView.Dispose();
m.ReleaseMutex();
This should ensure you cant dispose and invoke at the same time.

See also this question:
Avoiding the woes of Invoke/BeginInvoke in cross-thread WinForm event handling?
The utility class that resulted EventHandlerForControl can solve this problem for event method signatures. You could adapt this class or review the logic therein to solve the issue.
The real problem here is that nobugz is correct as he points out that the APIs given for cross-thread calls in winforms are inherently not thread safe. Even within the calls to InvokeRequired and Invoke/BeginInvoke themselves there are several race conditions that can cause unexpected behavior.

If a BackGroundWorker is a possibility, there's a very simple way to circumvent this:
public partial class MyForm : Form
{
private void InvokeViaBgw(Action action)
{
BGW.ReportProgress(0, action);
}
private void BGW_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (this.IsDisposed) return; //You are on the UI thread now, so no race condition
var action = (Action)e.UserState;
action();
}
private private void BGW_DoWork(object sender, DoWorkEventArgs e)
{
//Sample usage:
this.InvokeViaBgw(() => MyTextBox.Text = "Foo");
}
}

Handle the Form closing event. Check to see if your off UI thread work is still happening, if so start to bring it down, cancel the closing event and then reschedule the close using BeginInvoke on the form control.
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
if (service.IsRunning)
{
service.Exit();
e.Cancel = true;
this.BeginInvoke(new Action(() => { this.Close(); }));
}
}

The solution proposed by Isak Savo
try
{
myForm.Invoke(myForm.myDelegate, new Object[] { message });
}
catch (ObjectDisposedException)
{ //catch exception if the owner window is already closed
}
works in C# 4.0 but for some reasons it fails in C#3.0 (the exception is raised anyway)
So I used another solution based on a flag indicating if the form is closing and consequently preventing the use of invoke if the flag is set
public partial class Form1 : Form
{
bool _closing;
public bool closing { get { return _closing; } }
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_closing = true;
}
...
// part executing in another thread:
if (_owner.closing == false)
{ // the invoke is skipped if the form is closing
myForm.Invoke(myForm.myDelegate, new Object[] { message });
}
This has the advantage of completely avoiding the use of try/catch.

One way might be to call the method itself ones more instead of invoking the ImageListView-Method:
if (mImageListView != null &&
mImageListView.IsHandleCreated &&
!mImageListView.IsDisposed)
{
if (mImageListView.InvokeRequired)
mImageListView.Invoke(new YourDelegate(thisMethod));
else
mImageListView.RefreshInternal();
}
That way it would check one more time before finally calling RefreshInternal().

The suggestion to stop the thread generating the messages is not acceptable. Delegates can be multicast. Because one listener does not want to listen to the band, you don't shoot the band members.
Since the framework doesn't provide any easy way I know of to clear the message pump of those event messages, and since the form does not expose its private property that lets us know the form is closing:
Set a flag on the IsClosing Event of the window after you unsubscribe or stop listening to the events, and always check this flag before you do a this.Invoke().

i have same error. my error occurred in thread. finally i write this method :
public bool IsDisposed(Control ctrl)
{
if (ctrl.IsDisposed)
return true;
try
{
ctrl.Invoke(new Action(() => { }));
return false;
}
catch (ObjectDisposedException)
{
return true;
}
}

This works for me
if (this.IsHandleCreated){
Task.Delay(500).ContinueWith(_ =>{
this.Invoke(fm2);
});
} else {
this.Refresh();
}

Related

.NET Async in shutdown methods?

I have an application that connects to a REST API using async methods. I have this set up using async/await pretty much everywhere that connects to the API, however I have a question and some strange behavior that I don't completely understand. What I want to do is simply return a license in certain scenarios when the program shuts down. This is initiated by a window closing event; the event handler is as follows:
async void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
...other synchronous code...
//Check for floating licensing
if (KMApplication.License != null && KMApplication.License.Scope != Enums.LicenseScope.Standalone)
{
for (int i = 0; i < 3; i++)
{
try
{
await KMApplication.License.ShutDown(KMApplication.Settings == null
? Enums.LicenseReturnModes.PromptOnShutdown
: KMApplication.Settings.LicenseReturnMode)
.ConfigureAwait(false);
break;
}
catch (Exception ex)
{
_logger.Warn("Exception in license release, attempt " + i, ex);
}
}
}
await KMApplication.ApiService.Disconnect().ConfigureAwait(false);
_logger.Info("Shutdown Complete");
Application.Current?.Shutdown();
}
When this runs I can step through in the debugger and it gets to the first license shutdown call which is the first async awaited call. Then when I press F10 to step to the next line of code it just shuts down and is gone. I verified that the license release that is supposed to be happening in that line is in face happening so it appears to run to completion of that line but then shuts down or crashes or something. I also looked at the logs and it never gets to the Shutdown Complete line and I don't believe it's getting to the ApiService.Disconnect either.
I also tried running this as a sync method using Task.Run(() => ...the method...).GetAwaiter().GetResult() but that just deadlocks on the first call.
How do I handle this and have it run the async release, wait for it to be done, then shut down?
The fundamental problem in what you're trying to do is that async/await assumes the main application thread continues running. This assumption directly conflicts with the shutdown action, whose job is to terminate all running tasks.
If you examine the documentation on Window_Closing, it states the following (and only the following):
Occurs directly after Close() is called, and can be handled to cancel window closure.
This is important. The only thing this is supposed to do is allow you to programmatically cancel the window closure, thus prompting some additional user action.
Your expectations are befuddled because of how async/await works. Async/await appears to run in a linear fashion; however, what actually happens is that control is passed back to the caller at the first await. The framework assumes at that point that you do not wish to cancel the form close, and the program is allowed to terminate, taking all other actions with it.
Fundamentally, all C-style programs have a main entry point, which runs a loop. It's been that way since the early days of C, and continues that way in WPF. However, in WPF, Microsoft got a bit clever, and decided to hide this from the programmer. There are a couple of options to deal with things that need to happen after main window closing:
Re-hijack the main loop from your program, and put the code there. The details on how to do this may be found here.
Set an explicit shutdown mode, and kick off the task to initiate that. Call Application.Shutdown() as the very last line of code you need to execute.
Here is an async version of the FormClosing event. It delays the closing of the form until the completion of the supplied Task. The user is prevented from closing the form before the completion of the task.
The OnFormClosingAsync event passes an enhanced version of the FormClosingEventArgs class to the handling code, with two additional properties: bool HideForm and int Timeout. These properties are read/write, much like the existing Cancel property. Setting HideForm to true has the effect of hiding the form while the async operation is in progress, to avoid frustrating the user. Setting Timeout to a value > 0 has the effect of abandoning the async operation after the specified duration in msec, and closing the form. Otherwise it is possible that the application could be left running indefinitely with a hidden UI, which could certainly be a problem. The Cancel property is still usable, and can be set to true by the handler of the event, to prevent the form from closing.
static class WindowsFormsAsyncExtensions
{
public static IDisposable OnFormClosingAsync(this Form form,
Func<object, FormClosingAsyncEventArgs, Task> handler)
{
Task compositeTask = null;
form.FormClosing += OnFormClosing; // Subscribe to the event
return new Disposer(() => form.FormClosing -= OnFormClosing);
async void OnFormClosing(object sender, FormClosingEventArgs e)
{
if (compositeTask != null)
{
// Prevent the form from closing before the task is completed
if (!compositeTask.IsCompleted) { e.Cancel = true; return; }
// In case of success allow the form to close
if (compositeTask.Status == TaskStatus.RanToCompletion) return;
// Otherwise retry calling the handler
}
e.Cancel = true; // Cancel the normal closing of the form
var asyncArgs = new FormClosingAsyncEventArgs(e.CloseReason);
var handlerTask = await Task.Factory.StartNew(
() => handler(sender, asyncArgs),
CancellationToken.None, TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default); // Start in a thread-pool thread
var hideForm = asyncArgs.HideForm;
var timeout = asyncArgs.Timeout;
if (hideForm) form.Visible = false;
compositeTask = Task.WhenAny(handlerTask, Task.Delay(timeout)).Unwrap();
try
{
await compositeTask; // Await and then continue in the UI thread
}
catch (OperationCanceledException) // Treat this as Cancel = true
{
if (hideForm) form.Visible = true;
return;
}
catch // On error don't leave the form hidden
{
if (hideForm) form.Visible = true;
throw;
}
if (asyncArgs.Cancel) // The caller requested to cancel the form close
{
compositeTask = null; // Forget the completed task
if (hideForm) form.Visible = true;
return;
}
await Task.Yield(); // Ensure that form.Close will run asynchronously
form.Close(); // Finally close the form
}
}
private struct Disposer : IDisposable
{
private readonly Action _action;
public Disposer(Action disposeAction) => _action = disposeAction;
void IDisposable.Dispose() => _action?.Invoke();
}
}
public class FormClosingAsyncEventArgs : EventArgs
{
public CloseReason CloseReason { get; }
private volatile bool _cancel;
public bool Cancel { get => _cancel; set => _cancel = value; }
private volatile bool _hideForm;
public bool HideForm { get => _hideForm; set => _hideForm = value; }
private volatile int _timeout;
public int Timeout { get => _timeout; set => _timeout = value; }
public FormClosingAsyncEventArgs(CloseReason closeReason) : base()
{
this.CloseReason = closeReason;
this.Timeout = System.Threading.Timeout.Infinite;
}
}
Since OnFormClosingAsync is an extension method and not a real event, it can only have a single handler.
Usage example:
public Form1()
{
InitializeComponent();
this.OnFormClosingAsync(Window_FormClosingAsync);
}
async Task Window_FormClosingAsync(object sender, FormClosingAsyncEventArgs e)
{
e.HideForm = true; // Optional
e.Timeout = 5000; // Optional
await KMApplication.License.ShutDown();
//e.Cancel = true; // Optional
}
The Window_FormClosingAsync handler will run in a thread-pool thread, so it should not include any UI manipulation code.
Unsubscribing from the event is possible, by keeping a reference of the IDisposable return value, and disposing it.
Update: After reading this answer, I realized that it is possible to add a real event FormClosingAsync in the form, without creating a class that inherits from the form. This can be achieved by adding the event, and then running an initialization method that hooks the event to the native FormClosing event. Something like this:
public event Func<object, FormClosingAsyncEventArgs, Task> FormClosingAsync;
public Form1()
{
InitializeComponent();
this.InitFormClosingAsync(() => FormClosingAsync);
this.FormClosingAsync += Window_FormClosingAsync_A;
this.FormClosingAsync += Window_FormClosingAsync_B;
}
Inside the initializer, in the internal handler of the native FormClosing event, all the subscribers of the event can be retrieved
using the GetInvocationList method:
var eventDelegate = handlerGetter();
if (eventDelegate == null) return;
var invocationList = eventDelegate.GetInvocationList()
.Cast<Func<object, FormClosingAsyncEventArgs, Task>>().ToArray();
...and then invoked appropriately. All this adds complexity, while the usefulness of allowing multiple handlers is debated. So I would probably stick with the original single-handler design.
Update: It is still possible to have multiple handlers using the original method OnFormClosingAsync. It is quite easy actually. The Func<T>
class inherits from Delegate, so it has invocation list like a real event:
Func<object, FormClosingAsyncEventArgs, Task> aggregator = null;
aggregator += Window_FormClosingAsync_A;
aggregator += Window_FormClosingAsync_B;
this.OnFormClosingAsync(aggregator);
No modification in the OnFormClosingAsync method is required.
Ok here is what I ended up doing. Basically the window closing kicks off a task that will wait for the release to happen and then invoke the shutdown. This is what I was trying to do before but it didn't seem to work in async void method but it seems to be when done this way. Here is the new handler:
void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
...other sync code...
Task.Run(async () =>
{
await InvokeKmShutdown();
(Dispatcher ?? Dispatcher.CurrentDispatcher).InvokeShutdown();
});
}
And the shutdown method looks like this:
async Task InvokeKmShutdown()
{
...other sync code...
await KMApplication.ApiService.Disconnect();
//Check for floating licensing
if (KMApplication.License != null && KMApplication.License.Scope != License.Core.Enums.LicenseScope.Standalone)
{
for (int i = 0; i < 3; i++)
{
try
{
await KMApplication.License.ShutDown(KMApplication.Settings == null
? Enums.LicenseReturnModes.PromptOnShutdown
: KMApplication.Settings.LicenseReturnMode);
break;
}
catch (Exception ex)
{
_logger.Warn("Exception in license release, attempt " + i, ex);
}
}
}
}
Hope it helps someone.
EDIT
Note that this is with an WPF app set to ShutdownMode="OnExplicitShutdown" in App.xaml so it won't shut down the actual app until I call the shutdown. If you are using WinForms or WPF is set to shut down on last window or main window close (main window close is the default I believe) you will end up with the race condition described in the comments below and may get the threads shut down before things run to completion.

Crash from Invoke when MainForm is Disposed in FormClosing

I have an issue that relates to threading, cleaning up unmanaged resources and shutting down my app.
In the main UI thread I have a method that creates a new instance of class Worker. In Worker's constructor I start a new thread that has a while(Scanning) loop that updates some controls in my UI using Invoke() continuously (until Scanning bool is set to false). In the UI thread I raise the event FormClosing() whenever the application is closing down (through X button or Application.Exit() etc.). In FormClosing() I set Scanning to false and do some cleanup of unmanaged resources (that can only be done after the worker thread is done, because it uses those resources. The problem is that when I close the app down the MainForm apparently gets instantly disposed, so the app crashes at the Invoke (because it is trying to make a delegate run from UI thread, but that thread is disposed).
In an attempt to make the worker finish before the UI closes I tried to create a method StopWorker() in the worker class where I put Scanning = false, and then Thread.Join. As you can imagine the Join caused a deadlock as it makes the UI thread sleep but the Invoke needs the UI thread to move on.
In summary I need to cleanup unmanaged resources in FormClosing. I need the worker thread to be done before I do that though, as it uses these resources. The worker thread cannot finish (it uses Invoke) if the MainForm is disposed, therefore creating a tricky situation.
Based on Hans Passant's answer here, I created the below solution. It seems to be working very well.
In UI class/thread:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
var button = sender as Button;
if (button != null && string.Equals(button.Name, #"CloseButton"))
{
//FormClosing event raised by a user-created button action
}
else
{
//FormClosing event raised by program or the X in top right corner
//Do cleanup work (stop threads and clean up unmanaged resources)
if (_bw.Scanning)
{
_bw.Scanning = false;
ClosePending = true;
e.Cancel = true;
return;
}
//Code to clean up unmanaged resources goes here (dummy code below)
ApplicationLogger.Get.Log("Doing final cleanup work and exiting application...");
MemoryHandler.Get.Dispose();
ApplicationLogger.Get.Dispose();
}
}
My worker thread is in another class that has a public bool property called Scanning. It also has this while loop (notice the line at the bottom):
private void Worker()
{
while (Scanning)
{
Thread.Sleep(50);
_sendBackValue[0] = "lbOne";
_sendBackValue[1] = "blaBla";
_synch.Invoke(_valueDelegate, _sendBackValue);
_sendBackValue[0] = "lbTwo";
_sendBackValue[1] = "blaBla";
_synch.Invoke(_valueDelegate, _sendBackValue);
_sendBackValue[0] = "lbThree";
_sendBackValue[1] = "blaBla";
_synch.Invoke(_valueDelegate, _sendBackValue);
}
MainForm.Get.Invoke((Action)(() => MainForm.Get.StopScanning()));
}
Finally, back in the UI class/thread I have this method:
public void StopScanning()
{
if (!ClosePending) return;
ApplicationLogger.Get.Log("Worker thread is closing the application...");
Close();
}
Could you not better use the BackgroundWorker class/control? It is much easier to use because it has already a lot of synchronization stuff in it.
But if you have a separate thread, in your FormClosing event, use:
yourThread.Abort();
yourThread.Join(); // or yourThread.Join(1000); where 1000 is some kind of time out value
in your thread use try-excpet-finally construct
try
{
// do your stuff
}
catch (ThreadAbortException)
{
// do someting when your thread is aborted
}
finally
{
// do the clean up. Don't let it take too long.
}
Note that the Join command will block further execution until the thread has stopped. Therefore, I would recommend a not too high value for the time out parameter, otherwise the user interface will be blocked and will irritate users.
Disclaimer: I do not advocate the use of Thread, ManualResetEvent and, above all, volatile in the .NET 4.5+ era, but since the .NET version was not specified I've done my best to address the problem while keeping things as backwards-compatible as possible.
Here's a solution which uses a polling variable and a ManualResetEvent to block the execution of the FormClosing handler until the loop has completed - without any deadlocks. In your scenario if you have a class-level reference to the Thread which runs the loop, you can use Thread.Join instead of ManualResetEvent.WaitOne in the FormClosing handler - the semantics will be the same.
using System;
using System.Threading;
using System.Windows.Forms;
namespace FormClosingExample
{
public partial class Form1 : Form
{
private volatile bool Scanning = true;
private readonly ManualResetEvent LoopFinishedMre = new ManualResetEvent(false);
private readonly SynchronizationContext UiContext;
public Form1()
{
this.InitializeComponent();
// Capture UI context.
this.UiContext = SynchronizationContext.Current;
// Spin up the worker thread.
new Thread(this.Loop).Start();
}
private void Loop()
{
int i = 0;
while (this.Scanning)
{
// Some operation on unmanaged resource.
i++;
// Asynchronous UI-bound action (progress reporting).
// We can't use Send here because it will deadlock if
// the call to WaitOne sneaks in between the Scanning
// check and sync context dispatch.
this.UiContext.Post(_ =>
{
// Note that it is possible that this will
// execute *after* Scanning is set to false
// (read: when the form has already closed),
// in which case the control *might* have
// already been disposed.
if (this.Scanning)
{
this.Text = i.ToString();
}
}, null);
// Artifical delay.
Thread.Sleep(1000);
}
// Tell the FormClosing handler that the
// loop has finished and it is safe to
// dispose of the unmanaged resource.
this.LoopFinishedMre.Set();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// Tell the worker that it needs
// to break out of the loop.
this.Scanning = false;
// Block UI thread until Loop() has finished.
this.LoopFinishedMre.WaitOne();
// The loop has finished. It is safe to do cleanup.
MessageBox.Show("It is now safe to dispose of the unmanaged resource.");
}
}
}
Now, while this solution is (somewhat) tailored to your description of the problem (which I interpreted to the best of my ability), I had to make a large number of assumptions. If you want a better answer, you'll need to post a concise repro of the problem - not necessarily your production code, but at least a trimmed down working version which still has all the main nuts and bolts in place and exhibits the problem you've described.

Using Exceptions as Interrupts/Navigation. Is it a bad idea?

I am working on a basic windows forms application that have some functions doing 'Heavy' work. Because of this, I use ThreadAbortExceptions together with the help of a Background worker - like so:
public class AbortableBackgroundWorker : BackgroundWorker
-to cancel the executing functions. Let's call these functions "HeavyFunction()"
But, now that the ThreadAbortException has been caught inside the HeavyFunction(), I somehow need to get back to the "MainForm.cs" class which called the HeavyFunction(). This is to make sure I correctly close other open connections (ex. a Writer) and to show a message to the user. So, I just throw an exception from the HeavyFunction(), and then catch it in MainForm, like so(This is inside the HeavyFunction():
catch (ThreadAbortException tae)
{
//Deligate abortion upwards.
SomeWriter.DeleteAndClose();
throw new ArgumentException("relevant message or identifier for later use here");
//close and delete
}
The thrown exception is then caught in the "DoWork" function inside MainForm, and handled accordingly.
My Question - Is this a bad practice?
I am not that comfortable with Threads and Thread.Abort (Hence the backgroundworker in the first place)
Sub Question - What simple elegant solutions are there to bubble responses back up to the form from within a called class?
Is this a bad practice?
Yes, ThreadAbortException in general is a bad practice.
IMO, it will be much better, if MS didn't invent this exception ever, because many people consider TAE as a legal way to stop any operation.
So, I just throw an exception from the HeavyFunction()
What simple elegant solutions are there to bubble responses back
You've just re-invented TPL's OperationCancelledException.
Simple and elegant solution is to use TPL and its graceful cancellation pattern:
var cts = new CancellationTokenSource();
Task
.Factory
.StartNew(() =>
{
/* HeavyFunction */
while (someCondition)
{
cts.Token.ThrowIfCancellationRequested();
/* do something */
}
}, cts.Token);
If you want to do some actions only when your HeavyFunction was cancelled, add a continuation after StartNew:
.StartNew(/* */)
.ContinueWith(() => {/* some action */}, TaskContinuationOptions.OnlyOnCanceled);
BackgroundWorker supports cancellation scenario.
The UI thread has to call bw.CancelAsync() while inside DoWork you need to check for bw.CancellationPending property, if it's true you should exit DoWork.
private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
if (bw.WorkerSupportsCancellation == true)
{
bw.CancelAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; (i <= 10); i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Do something heavy
}
}
}

How to respond events while a threaded operation is running in .NET

I have a class to launch background operations in a WinForms application. I need to write this background worker since my requisites are using .NET 1.1, so I cannot use BackgroundWorker, that is only available from .NET 2.0
This class get a delegate and execute it in a thread. I want the main thread to respond to events.
I also want to indicate that the operation is running setting the application cursor to Cursors.WaitCursor.
What do you think about current implementation? I'm interested in the method WaitTillThreadFinishes(), because I'm not sure about Application.DoEvents(), please read the code and share with me opinions about WaitTillThreadFinishes.
The following code executes the operation:
private object ExecuteOperation (Delegate target, params object[] parameters)
{
mTargetDelegate = target;
mTargetParameters = parameters;
mTargetThread = new Thread(new ThreadStart(ThreadProc));
mTargetThread.Name = mTargetDelegate.Method.Name;
mOperationFinished = false;
// start threaded operation
mTargetThread.Start();
// perform active waiting
WaitTillThreadFinishes();
return mTargetResult;
}
The following code is executed in a thread, simply call the delegate, and wrap exceptions:
protected virtual void ThreadProc()
{
try
{
mTargetResult = mTargetDelegate.DynamicInvoke(mTargetParameters);
}
catch (ThreadAbortException) { }
catch (Exception ex)
{
//manage exceptions here ...
}
finally
{
mOperationFinished = true;
}
}
And this is the code performs an active waiting. I'm interested on share with you. Any better option? Any pain calling Application.DoEvents() massively?
private void WaitTillThreadFinishes ()
{
// Active wait to respond to events with a WaitCursor
while (!mOperationFinished)
{
// sleep to avoid CPU usage
System.Threading.Thread.Sleep(100);
Application.DoEvents();
Cursor.Current = Cursors.WaitCursor;
}
Cursor.Current = Cursors.Default;
}
Thanks in advance.
Please let me know if i understood your question correctly.
Why dont you use an event to notify the UI that the worker finished his job?
This way, the UI doen't get blocked by the worker, and you avoid busy waiting.
Sample Implementation
public class MyBackgroundWorker
{
// Fields
private Delegate _target;
private object[] _arguments;
// Events
public event EventHandler RunWorkerStarted;
public event EventHandler<RunWorkerCompletedEventArgs> RunWorkerCompleted;
// Event Invocators
public void InvokeRunWorkerStarted()
{
var handler = RunWorkerStarted;
if (handler != null) handler(this, new EventArgs());
}
public void InvokeRunWorkerCompleted(object result)
{
var handler = RunWorkerCompleted;
if (handler != null) handler(this, new RunWorkerCompletedEventArgs(result));
}
public void RunWorkerAsync(Delegate target, params object[] arguments)
{
_target = target;
_arguments = arguments;
new Thread(DoWork).Start(arguments);
}
// Helper method to run the target delegate
private void DoWork(object obj)
{
_target.DynamicInvoke(_arguments);
// Retrieve the target delegate's result and invoke the RunWorkerCompleted event with it (for simplicity, I'm sending null)
InvokeRunWorkerCompleted(null);
}
}
internal class RunWorkerCompletedEventArgs : EventArgs
{
public RunWorkerCompletedEventArgs(object result)
{
Result = result;
}
public object Result { get; set; }
}
Usage
In the UI you can use it this way:
private void button1_Click(object sender, EventArgs e)
{
var worker = new MyBackgroundWorker();
worker.RunWorkerStarted += worker_RunWorkerStarted;
worker.RunWorkerCompleted += worker_Completed;
worker.RunWorkerAsync(new MethodInvoker(SomeLengthyOperation), null);
}
void worker_RunWorkerStarted(object sender, EventArgs e)
{
}
void worker_Completed(object sender, EventArgs e)
{
MessageBox.Show("Worker completed");
}
private void SomeLengthyOperation()
{
Thread.Sleep(5000);
}
Final Notes
Remember to Invoke() in the event handlers to access the UI thread correctly. You can also modify the worker so this is done in a safe way.
There isn't much support in 1.1 for doing this, but I'll tell you what I'd do (sorry, no code at this time).
As for the asynchronous operation, I'd use the APM to kick off and complete the asynchronous method. This is fully supported in 1.1, so no worries there.
The idea is that in the UI, you store some indication that work is being done (a boolean field, for example) and (optionally) a Timer used to "wake up" the UI on a regular basis to check on the current status of the background work and indicate this to the user.
You would set the boolean to indicate you are working in the background, call BeginInvoke() on your delegate (using the overload that takes a callback search for "Executing a Callback Method When an Asynchronous Call Completes
"), and start the Timer. When the user attempts to use the UI, you would optionally check the boolean and cancel the operation, thus preventing the user from doing something harmful while you are waiting. When the timer Ticks, you can check the status of your asynchronous method by, say, a shared field that the method writes updates to and the UI reads. For example, a double which the UI uses to update a progress bar.
Once the callback fires, you clean up your asynchronous mess (i.e., call EndInvoke, and handle any exceptions thrown, etc), turn off the Timer and reset your boolean running indication field.
By using this method, you can keep the UI completely responsive (and partially usable, depending on your overall design), can set up a mechanism to abort the background worker (through the use of another field, the reverse of the boolean mentioned earlier, and inform the user of the status of the operation.
There is occasionally a case for kicking off a thread and waiting for its return, if you are doing other things in the meantime, but in this case, with the code you have shown, it is meaningless.
If you want the threadProc to allow for events to be processed, then call doevents in that, which will free up the CPU briefly, allowing for processing.
Unless you have a particular reason for needing to thread processes, you should not do it. Getting it right - as Ian Boyd has said - is difficult, and the more you need to interact with it the harder it is. If you can run fire-and-forget threads, that is the easiest.
Ideally you start the asynchronous operation and leave your form alone (aside from maybe using the Cursors.AppStarting cursor).
When your threaded operation completes, it then needs to fire some sort of BackgroundOperationComplete event. This is where your would call from your asynchronous delegate code:
form.Invoke(BackgroundOperationComplete);
The form's BackgroundOperationComplete method is where you can handle the fact that the background operation is complete:
void BackgroundOperationComplete()
{
this.Cursor = Cursors.DefaultCursor;
lblAnswer.Text = "The thread is done";
}
If all else fails, keep the operation synchronous, and use an IProgressDialog. (brief conceptual pseudo-code from memory):
void DoStuff()
{
IProgressDialog pd = new ProgressDialog();
pd.SetTitle = "Calculating Widgets";
pd.StartTimer(PDTIMER_RESET, NULL)
pd.StartProgressDialog(this.Handle, NULL, PROGDLG_MODAL | PROGDLG_NOTIME | PROGDLG_NOPROGRESSBAR | PROGDLG_NOCANCEL, NULL);
try
{
pd.SetLine(1, "Please wait while the widgets are frobbed");
DoTheThingThatDoesTheSynchronousStuff();
}
finally
{
pd.StopProgressDialog();
}
pd = null;
}

UI Thread .Invoke() causing handle leak?

In what circumstances would updating a UI control from a non-UI thread could cause the processes' handles to continually increase, when using a delegate and .InvokeRequired?
For example:
public delegate void DelegateUIUpdate();
private void UIUpdate()
{
if (someControl.InvokeRequired)
{
someControl.Invoke(new DelegateUIUpdate(UIUpdate));
return;
}
// do something with someControl
}
When this is called in a loop or on timer intervals, the handles for the program consistently increase.
EDIT:
If the above is commented out and amended as such:
public delegate void DelegateUIUpdate();
private void UIUpdate()
{
//if (someControl.InvokeRequired)
//{
// someControl.Invoke(new DelegateUIUpdate(UIUpdate));
// return;
//}
CheckForIllegalCrossThreadCalls = false;
// do something with someControl
}
...then the handles stop incrementing, however I don't want to allow cross thread calls, of course.
EDIT 2:
Here is a sample that shows the handles increase:
Thread thread;
private delegate void UpdateGUI();
bool UpdateTheGui = false;
public Form1()
{
InitializeComponent();
thread = new Thread(new ThreadStart(MyThreadLoop));
thread.Start();
}
private void MyThreadLoop()
{
while (true)
{
Thread.Sleep(500);
if (UpdateTheGui)
{
UpdateTheGui = false;
UpdateTheGuiNow();
}
}
}
private void UpdateTheGuiNow()
{
if (label1.InvokeRequired)
{
label1.Invoke(new UpdateGUI(UpdateTheGuiNow));
return;
}
label1.Text = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss");
label2.Text = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss");
label3.Text = DateTime.Now.ToString("MM-dd-yyyy HH:mm:ss");
}
private void btnInvoke_Click(object sender, EventArgs e)
{
UpdateTheGui = true;
}
I had the same problem with
this.Invoke(new DelegateClockUpdate(ChangeClock), sender, e);
creating one handle each call.
The handle increments because Invoke is Synchronous and effectively the handle has been left hanging.
Either a Wait Handle should be used to process the result or the Asynchronous BeginInvoke method as shown below.
this.BeginInvoke(new DelegateClockUpdate(ChangeClock), sender, e);
The Control.Invoke() method doesn't consume any handles. However, this code is clearly called from a thread. A Thread does consume handles, 5 of them.
The Thread class doesn't have a Dispose() method, although it ought to have one. That was probably by design, it would be very difficult to call reliably, impossibly so for threadpool threads. The 5 handles that a thread requires are released by the finalizer. Your program will require ever increasing amounts of handles if the finalizer never runs.
Not getting the finalizer to run is quite unusual. You would have to have a program that starts a lot of threads but doesn't allocate a lot of memory. This tends to only happen in static tests. You can diagnose this condition with Perfmon.exe, use the .NET memory performance counters and check if gen #0 collections are being done.
If this happens in a production program then you'll have to call GC.Collect() yourself to avoid a runaway handle leak.
I've seen the same thing in my code. I fixed it by replacing Invoke with BeginInvoke. The handle leak went away.
Doron.
I actually see the same problem occuring as JYelton. I have the same call from within a thread to update the UI.
As soon as the line someControl.Invoke(new DelegateUIUpdate(UIUpdate)); is called, the handle increases by one. There is certainly a leak of some kind on the invoke, but I have no idea what is causing it. This has been verified on several systems.
Aync call with explicit handle finalize. Exapmle:
public static class ActionExtensions
{
private static readonly ILog log = LogManager.GetLogger(typeof(ActionExtensions));
/// <summary>
/// Async exec action.
/// </summary>
/// <param name="action">Action.</param>
public static void AsyncInvokeHandlers(
this Action action)
{
if (action == null)
{
return;
}
foreach (Action handler in action.GetInvocationList())
{
// Initiate the asychronous call. Include an AsyncCallback
// delegate representing the callback method, and the data
// needed to call EndInvoke.
handler.BeginInvoke(
ar =>
{
try
{
// Retrieve the delegate.
var handlerToFinalize = (Action)ar.AsyncState;
// Call EndInvoke to free resources.
handlerToFinalize.EndInvoke(ar);
var handle = ar.AsyncWaitHandle;
if (handle.SafeWaitHandle != null && !handle.SafeWaitHandle.IsInvalid && !handle.SafeWaitHandle.IsClosed)
{
((IDisposable)handle).Dispose();
}
}
catch (Exception exception)
{
log.Error("Async Action exec error.", exception);
}
},
handler);
}
}
}
See http://msdn.microsoft.com/en-us/library/system.iasyncresult.asyncwaithandle.aspx note:
When you use the BeginInvoke method of a delegate to call a method asynchronously and obtain a wait handle from the resulting IAsyncResult, we recommend that you close the wait handle as soon as you are finished using it, by calling the WaitHandle.Close method. If you simply release all references to the wait handle, system resources are freed when garbage collection reclaims the wait handle, but garbage collection works more efficiently when disposable objects are explicitly closed or disposed. For more information, see the AsyncResult.AsyncWaitHandle property.
Here's an extension method which functions similarly to the normal Invoke call, but will clean up the handle after:
namespace ExtensionMethods
{
public static class ExtensionMethods
{
public static void InvokeAndClose(this Control self, MethodInvoker func)
{
IAsyncResult result = self.BeginInvoke(func);
self.EndInvoke(result);
result.AsyncWaitHandle.Close();
}
}
}
You can then call it very similarly to a normal invoke:
myForm.InvokeAndClose((MethodInvoker)delegate
{
someControl.Text = "New Value";
});
It will block and wait for the delegate to execute, then close the handle before returning.
This is the standard pattern for using Invoke to marshall updates to the UI thread.
Are you sure your problem is not being caused by other code in your application that is not included in your question?
I don't think it is related. Perhaps just waiting for the garbage collector to dispose the newly allocated object(s) inside Invoke().

Categories

Resources