UI Thread .Invoke() causing handle leak? - c#

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().

Related

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.

Best way to terminate a thread

I'm working on a downloader which downloads multiple files simultaneously. Each download has its own Form which runs the downloading code in a thread. I'm looking for the best approach to terminate the running download threads for two reasons
The download is cancelled by the user
The main form is closed
So far there are three approaches
Use a check variable like bool terminate
Use Thread.Abort()
Run the thread is a AppDomain and unload the AppDomain to terminate
Problem with the first approach is that threads keeps running until it hits the if statement. Even if the MainForm is closed the process keeps on running until all the downloading threads are terminated.
I don't know much about Thread.Abort but it is highly discouraged.
Here is the code for the last approach:
public class Processor : MarshalByRefObject
{
private AsyncOperation _operation;
private AppDomain Domain { get; set; }
public delegate void ProgressChangedEventHnadler(Processor sender, int progress);
public delegate void ProcessedEventHandler(Processor sender, EventArgs e);
public delegate void ExceptionOccuredEventHandler(Processor sender, Exception ex);
public event ProgressChangedEventHnadler ProgressChanged;
public event ProcessedEventHandler Processed;
public event ExceptionOccuredEventHandler ExceptionOccured;
private void OnProgressChanged(int progress)
{
if(ProgressChanged!=null)
ProgressChanged.Invoke(this,progress);
}
private void OnProcessed(EventArgs e)
{
if (Processed != null)
Processed.Invoke(this, e);
}
private void OnExceptionOccured(Exception ex)
{
if (ExceptionOccured != null)
ExceptionOccured.Invoke(this,ex);
}
public Processor()
{
_operation = AsyncOperationManager.CreateOperation(null);
}
public static Processor CreateInstance()
{
var locaion = Assembly.GetEntryAssembly().Location;
var domain = AppDomain.CreateDomain(Guid.NewGuid().ToString());
var instance =(Processor)domain.CreateInstanceFromAndUnwrap(locaion, typeof (Processor).FullName);
instance.Domain = domain;
return instance;
}
public void Start()
{
var mainThread = new Thread(Process);
mainThread.Start();
}
public void Stop()
{
AppDomain.Unload(Domain);
}
private void Process()
{
//Do the Work and raise events like
//_operation.Post(e => OnProcessed((EventArgs)e), EventArgs.Empty);
}
}
In general you have two options:
allow the thread to terminate itself. This covers your first option.
terminate the thread externally. This covers your other options.
And that's it. And none of them, in general, can prevent the threads from running for indefinite time after they should (from the programmer's intent point of view) terminate.
The most predictable approach is the first one. If terminating takes too long, try to do the processing in smaller steps to allow checking the termination flag more frequently. Also, note the IsBackground flag which will help with the application being unable to close itself.
The whole problem with the other options is that any code (except for some special cases like finally blocks) can be just interrupted in the middle of its execution, which can lead to some undesired results (e.g. some unmanaged resources not released) - as it is explained in Thread.Abort documentation.
Note that the third approach in the newest versions of .NET framework is equivalent to calling the Abort method on your executing threads, as explained in the documentation:
The threads in domain are terminated using the Abort method, which throws a ThreadAbortException in the thread. Although the thread should terminate promptly, it can continue executing for an unpredictable amount of time in a finally clause.
So it seems better to use Thread.Abort from these two, as it's simpler and more readable.
If the first approach is problematic, and if you are well aware of the type of operations your thread is executing and there is no problem in interrupting them in-between then the "brutal" approach should be fine.

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;
}

Why would InvokeRequired=False via a Delegate.BeginInvoke?

For what reasons would this.InvokeRequired equal False within InitUIState(), as this new thread is being created via a delegate?
My problem is that my label is never being set and this.BeginInvoke() is never executing, I imagine it's due to the fact InvokeRequired = False.
private delegate void BackgroundOperationDelegate(ViewMode mode);
private BackgroundOperationDelegate backgroundOperationDelegate;
private void FormControlPanel_Load(object sender, EventArgs e)
{
Init();
}
private void Init() {
this.backgroundOperationDelegate = this.InitUIState;
this.backgroundOperationDelegate.BeginInvoke(mode, null, null);
}
private void InitUIState(ViewMode mode)
{
// .. other business logic only here relevant
// to the worker process ..
this.BeginInvoke((MethodInvoker)delegate
{
this.labelProgramStatus.Text = CONSOLE_IDLE_STATUS;
});
}
I use this pattern time and time again, but for some reason, this time it's not executing :P
(and yes there is only one instance of InitUIState() ever being called, that being from the delegate)
Thanks guys.
Images verifying two distinct threads:
http://imgur.com/mq12Wl&X5R7G
http://imgur.com/mq12W&X5R7Gl
Follow up question: Is this an unpreferred way of creating threads? I've just always found it so simple and lightweight. Perhaps I should be using thread.Start() and I will avoid these issues?
Your 2nd BeginInvoke will throw an Exception.
Try
private void InitUIState(ViewMode mode)
{
if (this.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate
{
InitUIState(mode);
});
}
else
{
this.labelProgramStatus.Text = CONSOLE_IDLE_STATUS;
}
}
You are mixing BeginInvoke of Form and Delegate, as both of them have same method name.
Form's method, BeginInvoke calls the method you are requested in the same UI thread, but on a later stage, after processing its own pending UI operations. This is the reason, InvokeRequired will always be false within the Form's BeginInvoke's method.
Delegate's method, BeginInvoke calls the method on a new thread asynchronously in thread pool. And InvokeRequired in delegate's BeginInvoke will always be true.
Invoke and BeginInvoke on delegates are not the same as ISynchronizeInvoke.
Also you need to call EndInvoke when dealing with a delegate.

Avoid calling Invoke when the control is disposed

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();
}

Categories

Resources