Related
I have a form that spawns a BackgroundWorker, that should update form's own textbox (on main thread), hence Invoke((Action) (...)); call.
If in HandleClosingEvent I just do bgWorker.CancelAsync() then I get ObjectDisposedException on Invoke(...) call, understandably. But if I sit in HandleClosingEvent and wait for bgWorker to be done, than .Invoke(...) never returns, also understandably.
Any ideas how do I close this app without getting the exception, or the deadlock?
Following are 3 relevant methods of the simple Form1 class:
public Form1() {
InitializeComponent();
Closing += HandleClosingEvent;
this.bgWorker.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
while (!this.bgWorker.CancellationPending) {
Invoke((Action) (() => { this.textBox1.Text = Environment.TickCount.ToString(); }));
}
}
private void HandleClosingEvent(object sender, CancelEventArgs e) {
this.bgWorker.CancelAsync();
/////// while (this.bgWorker.CancellationPending) {} // deadlock
}
The only deadlock-safe and exception-safe way to do this that I know is to actually cancel the FormClosing event. Set e.Cancel = true if the BGW is still running and set a flag to indicate that the user requested a close. Then check that flag in the BGW's RunWorkerCompleted event handler and call Close() if it is set.
private bool closePending;
protected override void OnFormClosing(FormClosingEventArgs e) {
if (backgroundWorker1.IsBusy) {
closePending = true;
backgroundWorker1.CancelAsync();
e.Cancel = true;
this.Enabled = false; // or this.Hide()
return;
}
base.OnFormClosing(e);
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (closePending) this.Close();
closePending = false;
// etc...
}
I've found another way. If you have more backgroundWorkers you can make:
List<Thread> bgWorkersThreads = new List<Thread>();
and in every backgroundWorker's DoWork method make:
bgWorkesThreads.Add(Thread.CurrentThread);
Arter that you can use:
foreach (Thread thread in this.bgWorkersThreads)
{
thread.Abort();
}
I used this in Word Add-in in Control, which i use in CustomTaskPane. If someone close the document or application earlier then all my backgroundWorkes finishes their work, it raises some COM Exception(I don't remember exatly which).CancelAsync() doesn't work.
But with this, I can close all threads which are used by backgroundworkers Immediately in DocumentBeforeClose event and my problem is solved.
Here was my solution (Sorry it's in VB.Net).
When I run the FormClosing event I run BackgroundWorker1.CancelAsync() to set the CancellationPending value to True. Unfortunately, the program never really gets a chance to check the value CancellationPending value to set e.Cancel to true (which as far as I can tell, can only be done in BackgroundWorker1_DoWork).
I didn't remove that line, although it doesn't really seem to make a difference.
I added a line that would set my global variable, bClosingForm, to True. Then I added a line of code in my BackgroundWorker_WorkCompleted to check both e.Cancelled as well as the global variable, bClosingForm, before performing any ending steps.
Using this template, you should be able to close your form out at any time even if the backgroundworker is in the middle of something (which might not be good, but it's bound to happen so it might as well be dealt with). I'm not sure if it's necessary, but you could dispose the Background worker entirely in the Form_Closed event after this all takes place.
Private bClosingForm As Boolean = False
Private Sub SomeFormName_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
bClosingForm = True
BackgroundWorker1.CancelAsync()
End Sub
Private Sub backgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'Run background tasks:
If BackgroundWorker1.CancellationPending Then
e.Cancel = True
Else
'Background work here
End If
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If Not bClosingForm Then
If Not e.Cancelled Then
'Completion Work here
End If
End If
End Sub
Can you not wait on the signal in the destructor of the form?
AutoResetEvent workerDone = new AutoResetEvent();
private void HandleClosingEvent(object sender, CancelEventArgs e)
{
this.bgWorker.CancelAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (!this.bgWorker.CancellationPending) {
Invoke((Action) (() => { this.textBox1.Text =
Environment.TickCount.ToString(); }));
}
}
private ~Form1()
{
workerDone.WaitOne();
}
void backgroundWorker1_RunWorkerCompleted( Object sender, RunWorkerCompletedEventArgs e )
{
workerDone.Set();
}
Firstly, the ObjectDisposedException is only one possible pitfall here. Running the OP's code has produced the following InvalidOperationException on a substantial number of occasions:
Invoke or BeginInvoke cannot be called
on a control until the window handle
has been created.
I suppose this could be amended by starting the worker on the 'Loaded' callback rather than the constructor, but this entire ordeal can be avoided altogether if BackgroundWorker's Progress reporting mechanism is used. The following works well:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (!this.bgWorker.CancellationPending)
{
this.bgWorker.ReportProgress(Environment.TickCount);
Thread.Sleep(1);
}
}
private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.textBox1.Text = e.ProgressPercentage.ToString();
}
I kind of hijacked the percentage parameter but one can use the other overload to pass any parameter.
It is interesting to note that removing the above sleep call clogs the UI, consumes high CPU and continually increases the memory use. I guess it has something to do with the message queue of the GUI being overloaded. However, with the sleep call intact, the CPU usage is virtually 0 and the memory usage seems fine, too. To be prudent, perhaps a higher value than 1 ms should be used? An expert opinion here would be appreciated... Update: It appears that as long as the update isn't too frequent, it should be OK: Link
In any case, I can't foresee a scenario where the updating of the GUI has to be in intervals shorter than a couple of milliseconds (at least, in scenarios where a human is watching the GUI), so I think most of the time progress reporting would be the right choice
I really dont see why DoEvents is regarded as such a bad choice in this case if you are using this.enabled = false. I think it would make it quite neat.
protected override void OnFormClosing(FormClosingEventArgs e) {
this.Enabled = false; // or this.Hide()
e.Cancel = true;
backgroundWorker1.CancelAsync();
while (backgroundWorker1.IsBusy) {
Application.DoEvents();
}
e.cancel = false;
base.OnFormClosing(e);
}
Your backgroundworker should not use Invoke to update the textbox. It should ask the UI thread nicely to update the textbox using event ProgressChanged with the value to put in the textbox attached.
During event Closed (or maybe event Closing), the UI thread remembers that the form is closed before it cancels the backgroundworker.
Upon receiving the progressChanged the UI thread checks if the form is closed and only if not, it updates the textbox.
This won't work for everyone, but if you are doing something in a BackgroundWorker periodically, like every second or every 10 seconds, (perhaps polling a server) this seems to work well to stop the process in an orderly manner and without error messages (at least so far) and is easy to follow;
public void StopPoll()
{
MyBackgroundWorker.CancelAsync(); //Cancel background worker
AutoResetEvent1.Set(); //Release delay so cancellation occurs soon
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
while (!MyBackgroundWorker.CancellationPending)
{
//Do some background stuff
MyBackgroundWorker.ReportProgress(0, (object)SomeData);
AutoResetEvent1.WaitOne(10000);
}
}
I'd pass in the SynchronizationContext associated with the textbox to the BackgroundWorker and use that to perform Updates on the UI thread. Using SynchronizationContext.Post, you can check if the control is disposed or disposing.
What about Me.IsHandleCreated?
Private Sub BwDownload_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BwDownload.RunWorkerCompleted
If Me.IsHandleCreated Then
'Form is still open, so proceed
End If
End Sub
Another way:
if (backgroundWorker.IsBusy)
{
backgroundWorker.CancelAsync();
while (backgroundWorker.IsBusy)
{
Application.DoEvents();
}
}
One solution that works, but too complicated. The idea is to spawn the timer that will keep trying to close the form, and form will refuse to close until said bgWorker is dead.
private void HandleClosingEvent(object sender, CancelEventArgs e) {
if (!this.bgWorker.IsBusy) {
// bgWorker is dead, let Closing event proceed.
e.Cancel = false;
return;
}
if (!this.bgWorker.CancellationPending) {
// it is first call to Closing, cancel the bgWorker.
this.bgWorker.CancelAsync();
this.timer1.Enabled = true;
}
// either this is first attempt to close the form, or bgWorker isn't dead.
e.Cancel = true;
}
private void timer1_Tick(object sender, EventArgs e) {
Trace.WriteLine("Trying to close...");
Close();
}
I have a WPF control that is being handle, render and displayed in the main thread of my application. The control uploads thousands of data points into view in an object called "Layer." Here is a rough description of how the object/class hierarchy looks like:
public class WPFControl{
private List<Layer> myLayers;
public List<Layer> MyLayers{
get{ return myLayer;}
}
...
}
public class Layer{
private List<DataPoint> myDataPoints;
public List<DataPoint> MyDataPoints{
get{ return myDataPoints;}
}
...
}
public class DataPoint{
....
}
Since the creation process of this "Layer" object takes some time because of the thousands of DataPoint it has to read and upload, I am creating that layer object in a different thread. That works great and returns the Layer object very nicely. The problem is when I try to do add it to the WPF control to be displayed like this:
myWpfControl.MyLayers.Add(layerCreatedInOtherThread);
the WPF control fires this error:
The calling thread cannot access this object because a different thread owns it
I thought, ok, I can then use the dispatcher like so:
myWpfControl.Dispatcher.Invoke((Action)
(()=>{
myWpfControl.MyLayers.Add(layerCreatedInOtherThread);
})
);
But I keep getting the same error. Any ideas how I can get around this?
Using a BackgroundWorker you can run a task on another thread and then when it is completed have access to the results from the UI thread.
private System.ComponentModel.BackgroundWorker bgWorker;
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
//Start the work
bgWorker.RunWorkerAsync(null) //you can send an argument instead of null
Do the work
private void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker worker = sender as BackgroundWorker;
// Assign the result of the computation
// to the Result property of the DoWorkEventArgs
// object. This is will be available to the
// RunWorkerCompleted eventhandler.
e.Result = CreateLayerInOtherThread(); //if you sent an arg instead of null it as availalbe in e.Argument and can be cast from object.
}
Get the result once completed. This runs on the UI thread so you can update it.
private void bgWorker_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
// First, handle the case where an exception was thrown.
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
// Next, handle the case where the user canceled
// the operation.
// Note that due to a race condition in
// the DoWork event handler, the Cancelled
// flag may not have been set, even though
// CancelAsync was called.
}
else
{
// Finally, handle the case where the operation
// succeeded.
Layer myLayer = (Layer)e.Result;
myWpfControl.MyLayers.Add(myLayer);
}
}
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;
}
Is there a better way to do implement a simple lock like below?
I only want to to the "DOSOMETHING" if it's not already being run. Should I be using reall locks here? if I use lock will that cause everything to queue up and wait for the lock to release? (that's not what I want!)
Thanks
bool running = false;
void DataDisplayView_Paint(object sender, PaintEventArgs e)
{
// if (!this.initialSetDone)
if (!running)
{
this.running = true;
//DOSOMETHING
this.running = false;
}
}
No, you do not want to use locks here. This is not a thread synchronization problem. This is a method reentrancy problem.
You might try something like this.
bool running = false;
void DataDisplayView_Paint(object sender, PaintEventArgs e)
{
if (!this.running)
{
this.running = true;
try
{
//DOSOMETHING
}
finally
{
this.running = false;
}
}
}
You just need to synchronise (lock is the simplest way) bits of the code:
bool running = false;
readonly object padlock = new object();
void DataDisplayView_Paint(object sender, PaintEventArgs e)
{
if (!this.initialSetDone)
{
lock(padlock)
{
if(running) return;
running = true;
}
try {
//DOSOMETHING
}
finally
{
lock(padlock)
{
this.running = false;
}
}
}
}
The best way is to use a try/finally block
try {
this.running = true;
...
} finally {
this.running = false;
}
Real thread locks are only needed if this method is called from multiple threads. Given that it appears to be a paint event handler this is unlikely as controls are affinitized to a single thread.
Am I missing something? The code as you've posted it does not seem to do anything. That is, the code will run whether or not running is true.
Generally, any code that tries to "lock" itself like this...
if (!running)
{
running = true;
try
{
// This code should not call itself recursively.
// However, it may execute simultaneously on more than one thread
// in very rare cases.
}
finally
{
running = false;
}
}
...is perfectly good, as long as you're in a single-threaded scenario. If you're running multi-threaded code, problems can arise because you are assuming that no two threads will reach the if (!running) line at the same time.
The solution in multi-threaded code is to use some form of atomic switch. I've used the AutoResetEvent for this purpose:
var ready = new AutoResetEvent(true);
if (ready.WaitOne(0))
{
try
{
// This code will never be running on more than one thread
// at a time.
}
finally
{
ready.Set();
}
}
Note that if you're having reentrancy on your paint callback, you've got a more serious problem. Paint handlers should be blocking your message pump (and should complete relatively quickly), so you should never see this case. The only exception is if you call Application.DoEvents() from somewhere in your paint handler, which you really shouldn't be doing.
You shift varaible names in the middle, so I'm going to assume you wanted:
bool running = false;
void DataDisplayView_Paint(object sender, PaintEventArgs e)
{
if (!this.running)
{
this.running = true;
//DOSOMETHING
this.running = false;
}
}
The problem you have here is that if DataDisplayView_Paint can be called from multiple threads, then it is possible that between the if (!this.running) and the this.running = true; the other thread could jump in and start DOSOMETHING (because running is still false). Then the first thread will resume, and start DOSOMETHING again. If that is a possiblity, then you will need to use a real lock.
If you use Monitor.TryEnter instead you could specify a timeout, in which case the result you get is such that:
only one thread can run the DOSOMETHING at a time
subsequent calls will try to get the lock and give up after the timeout clause
If you don't provide with a timeout, or set the timeout to 0, this call won't block and will return immediately (maybe that'd suit your requirement better?):
if (!this.initialSetDone && Monitor.TryEnter(_lock))
{
// DOSOMETHING
}
Alternatively, you can make the running variable volatile so that you will always get the latest value stored in the variable:
private volatile bool running;
if (!this.initialSetDone && !this.running) // #1
{
this.running = true;
try
{
// DOSOMETHING
}
finally
{
this.running = false;
}
}
The second approach won't queue up subsequent calls, but there is the possibility that two threads will both hit #1 and evaluate that it's safe to proceed then both end up running DOSOMETHING, though it's highly unlikely.
I only want to to the "DOSOMETHING" if
it's not already being run
Your question doesn't have enough information, so I can't help but make assumptions about your code.
My first assumption is that, based on the signature DataDisplayView_Paint(object s, PaintEventArgs e), your code runs on the GUI thread.
My second assumption is that your code DOSOMETHING is synchronous.
With that in mind, here's version of your code which guarantees we only run DOSOMETHING if its not already being run:
void DataDisplayView_Paint(object s, PaintEventArgs e)
{
//DOSOMETHING
}
The GUI thread will only process one message at a time, and your DataDisplayView_Paint method does not exit until DOSOMETHING completes. If you're doing anything with the GUI like drawing to a Graphics object or changing labels, then this code won't get invoked from more than one thread -- and if it does, .NET will throw an exception. In other words, you don't need any synchronization.
Let's assume DOSOMETHING runs asyncronously -- now we have an interesting problem, but its very easy to solve, and you don't need any bools.
Essentially, all you're doing is disabling your event handler while DOSOMETHING runs, then re-enabling it. Instead of using a bool, unhook and rehook your event handler as needed:
void DataDisplayView_Paint(object s, PaintEventArgs e)
{
DataDisplayView.Paint -= DataDisplayView_Paint;
DoSomethingAsynchronously(); // re-hooks event handler when completed
}
void DoSomethingAsychronously()
{
ThreadPool.QueueUserWorkItem(() =>
{
try
{
// DOSOMETHING
}
finally
{
// may need a lock around this statement
DataDisplayView.Paint += DataDisplayView_Paint;
}
});
}
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().