I am a newbie to events and I am asking myself if a event that gets triggered (from a SDK) is executed on the main thread or async on another.
Can anyone help me how to check this?
This for example gets executed if the event fires and it doesn't block the UI, which surprises me (triggered max. speed each 0.05 seconds):
void TrackingOnNewTrackingObservations(object sender, TrackingEventArgs e)
{
try
{
dgvTracking.Rows[0].Cells["cName"].Value = "SlopeDistance";
dgvTracking.Rows[0].Cells["cValue"].Value = string.Format("{0:0.00} m", e.SlopeDistance);
dgvTracking.Rows[1].Cells["cName"].Value = "HorizontalAngle";
dgvTracking.Rows[1].Cells["cValue"].Value = string.Format("{0:0.00000}°", e.HorizontalAngle);
dgvTracking.Rows[2].Cells["cName"].Value = "VerticalAngle";
dgvTracking.Rows[2].Cells["cValue"].Value = string.Format("{0:0.00000}°", e.VerticalAngle);
}
catch (Exception ex)
{
Debug.WriteLine("Error TrackingOnNewTrackingObservations ->" + ex.Message);
}
Use Corewindow.Dispatcher.HasThreadAccess to test whether or not the execution is on the UI thread.
Normally events are going to be invoked on the same thread as the invocation of the method that led to the event. If the class is a UI class them this is going to be the UI thread.
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
}
}
}
I have a BackgroundWorker that I call from my main UI thread as follows.
On the MainWindow I declare the BackgroundWorker
private BackgroundWorker backgroundWorkerRefreshFromWeb = new BackgroundWorker();
And in the constructor I set it up as follows.
backgroundWorkerRefreshFromWeb.WorkerReportsProgress = true;
backgroundWorkerRefreshFromWeb.WorkerSupportsCancellation = true;
backgroundWorkerRefreshFromWeb.DoWork +=
new DoWorkEventHandler(backgroundWorkerRefreshFromWeb_DoWork);
backgroundWorkerRefreshFromWeb.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(backgroundWorkerRefreshFromWeb_RunWorkerCompleted);
backgroundWorkerRefreshFromWeb.ProgressChanged +=
new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
At the end of the constructor I call the following method to start it on its way.
private void RefreshWebDataTimer(Object state)
{
if (!backgroundWorkerRefreshFromWeb.IsBusy && !backgroundWorkerLoadFromDB.IsBusy)
{
System.Diagnostics.Debug.Print("Refresh Timer Started at {0}", DateTime.Now);
backgroundWorkerRefreshFromWeb.RunWorkerAsync(nfl);
}
}
The DoWork event handler calls a method from another project (DLL). That method has a pattern which calls multiple threads to do process work. when one of those threads throws an error, the application crashed and the BackgroundWorker does not catch it in the RunWorkerCompleted event. The pattern is a complex (probably overly complicated) but is as follows.
In the method the DoWork event handler calls I create a set of "sub-worker" threads in a wrapper as follows...and then WAIT for all threads to finish processing before moving on.
private static void GetRoster(Nfl teams, ref ManualResetEvent[] mre, ref int index)
{
mre = new ManualResetEvent[Dictionary.NUMBER_OF_NFL_TEAMS];
ParseDataAsyncWrapper[] dw = new ParseDataAsyncWrapper[Dictionary.NUMBER_OF_NFL_TEAMS];
index = 0;
foreach (NflTeam team in teams)
{
//Get Roster and create players
mre[index] = new ManualResetEvent(false);
dw[index] = new ParseDataAsyncWrapper(team, mre[index]);
ThreadPool.QueueUserWorkItem(new WaitCallback(dw[index].RosterCallbackAsync), index++);//Don't fully understand this
Thread.Sleep(wait.Next(Dictionary.THREAD_WAIT_MS));
}
foreach (ManualResetEvent re in mre) { if (re != null) { re.WaitOne(); } } //Wait for all threads to finish
mre = null; //allow to be disposed
dw = null;
}
I use the callback for each thread to get a webpage and then process that page:
internal async void RosterCallbackAsync(object State)
{
if (Thread.CurrentThread.Name == null) { Thread.CurrentThread.Name = string.Format("Roster{0}", State); }
WebPage = await Html.WebClientRetryAsync(Dictionary.ROSTER_WEBPAGE.Replace(Dictionary.CITY_REPLACE_STR, this.Team.CityAbr));
Html.ParseRoster(WebPage, Team);
DoneEvent.Set();
}
I am then throwing the exception in Html.ParseRoster but it is not getting caught. This is on a different thread than the BackgroundWorker. I don't know why the BackgroundWorker is not catching it. Since I am waiting for all threads to finish before moving on I don't think the RunWorkerCompleted event would run before I am done here.
I've looked at the help page for Application.DispatcherUnhandledException event and it states:
you will need to write code to do the following: Handle exceptions on
the background thread. Dispatch those exceptions to the main UI
thread. Rethrow them on the main UI thread without handling them to
allow DispatcherUnhandledException to be raised.
My question is 1) Why is the excpetion not being caught? Should I use Application.DispatcherUnhandledException and if so how can I accomplish this? I would ultimately like to throw these exceptions to the BackgroundWorker. Any suggestions or comments would be greatly appreciated.
UPDATE
I have been working on using TPL with await/async and Tasks and updated my code. This has been somewhat successfull as I am now getting the exception back to the BackgroundWorker. Ignoring how I get the exception back to the DoWork event for now ... I check that I am getting an exception by adding a try/catch block and am catching and re-throwing the exception. Here is my DoWork event
private async void backgroundWorkerRefreshFromWeb_DoWork(object sender, DoWorkEventArgs e)
{
// Do not access the form's BackgroundWorker reference directly.
// Instead, use the reference provided by the sender parameter.
BackgroundWorker bw = sender as BackgroundWorker;
// Start the time-consuming operation.
NflStatsComplete = false;
bw.ReportProgress(0, "Starting Data Refresh from Web...");
try
{
e.Result = await Html.RetrieveWebData(bw, e);
}
catch (Exception ex)
{
throw;
}
// If the operation was canceled by the user,
// set the DoWorkEventArgs.Cancel property to true.
if (bw.CancellationPending)
{
e.Cancel = true;
}
}
In the debugger I get an exception and see it thrown. However, when it then goes to the RunWorkerCompleted event the RunWorkerCompletedEventArgs e shows e.Error == null. I don't understand how this can be since I am throwing an exception directly from the DoWork event. Can someone explain this behavior?
The Backgroundworker is setup as an async method. I believe this is causing the RunWorkerCompleted event to fire before the DoWork event has completed and the exception has been raised. By updating the DoWork method to remove the async compiler keyword and removing any awaits the exception propogates back to the method specified by the RunWorkerCompleted event and e.Error != null
I want to know what can be problem if i have the following POC...
public void DoProcess() // called as Do_Work
{
textUpdater = null;
try
{
SetButtonEnabled(false);
aHandler = new DataHandler();
aHandler.Initialize(_configuration);
aHandler.GetDataFromWebAndSave();
MessageBox.Show("completed");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + " \r\n\r\n" + ex.StackTrace);
}
SetButtonEnabled(true);
}
Usually a backgroundWorker process includes a loop where one can easily see whether cancel is called or not. In my case, i can't check ...
Say I CLOSE the windows form (containing above code). Will everything be terminated safely ??
If not, then how can i do it ?
(i guess other way could be 'use thread').
The thread proc of your backgroundworker doesn't have to have a loop. And it doesn't have to be cancelled to finish. It simply finishes when... the proc exits!
When it finishes, RunWorkerCompleted will be called.
I see a major problem in your call though: You manipulate your GUI from the background thread. This is a no-no! All manipulations of a GUI element must be made from the thread that created the element. In your case, use ReportProgress() to delegate status information to the ProgressChanged handler that will execute it in the foreground thread.
In addition, as Rewinder wrote, you can cancel the worker from FormClosing(). But if you never monitor CancellationPending from your worker proc, this is pointless.
If you want to be sure your backgroundworker is cancelled, you can do something like this:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
myBackgroundWorker.CancelAsync();
}
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();
}