BackgroundWorker.IsBusy not 100% reliable? - c#

I sometimes get an Exception that my BackgroundWorker is already running after checking it's state with the IsBusy method.
Code:
if(!_worker.IsBusy)
_worker.RunWorkerAsync(stateObj); //<-- exception is thrown here
I don't ever call the worker from anywhere else, so I'm stumped on how to handle this. Should I just ignore it? Or have it call itself?
(e.g.)
void CallWorker(object stateObj)
{
try
{
if(!_worker.IsBusy)
_worker.RunWorkerAsync(stateObj);
}
catch (Exception e)
{
//ignore OR
//CallWorker(stateObj);
}
}

Related

Backgroundworker can't handle exception

I have a background worker that will throw an exception when there is a problem. I'm trying to catch the exception in the workcompleted event.
My code is roughly as follows:
void workerProcessReports_DoWork(object sender, DoWorkEventArgs e)
{
try
{
//Work is here. The code here throws an exception
}
catch (Exception ex)
{
throw ex;
}
}
void workerProcessReports_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show("There was a problem");
}
else
{
MessageBox.Show("No Problems");
}
}
The problem is that visual studio breaks on the throw ex in the dowork method with the Message
InvalidOperationException was unhandled by user code
What's going on?
Don't catch and rethrow your same exception, that's a waste and causes your stack trace to get messed up.
If you want the exact same exception to be thrown after catching it from a parent exception type, just write throw; in your catch block. If you plan on just throwing everything anyway, don't bother catching it in the first place.
If you do allow your exception to occur without handling it in the doWork method, then you can throw on the parent thread in your RunWorkerCompleted method.
Within your RunWorkerCompleted method you can throw it as such:
if(e.Error != null)
{
throw e.Error;
}
However, at this point if it's something you can handle you may just want to recover and continue, instead of throwing since you are already aware that an exception occured. Especially, if this parent thread is your UI thread, then this is the perfect opportunity to display an error message instead of throwing and potentially crashing your application for a non-fatal error.

Background worker doesn't catch errors from ThreadPool

I'm using a BackgroundWorker since I need to give a feedback in my UI. I also need to use ThreadPool in my class for it to run asynchronously but it seems that my background worker cannot catch the exception it throws.
It's intended to give a feedback on what task it's doing.
I made a simple application which reproduces the problem :
// MAIN UI CLASS
BackgroundWorker _bgWorker = new BackgroundWorker();
void _bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
// Returns custom error
MessageBox.Show(e.Error.Message);
}
}
void _bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
try {
// Initialize test error class
var testClass = new TestClass();
}
catch (Exception ex)
{
MessageBox.Show("im from trycatch");
}
}
private void Window_ContentRendered(object sender, EventArgs e)
{
_bgWorker.DoWork += _bgWorker_DoWork;
_bgWorker.RunWorkerCompleted += _bgWorker_RunWorkerCompleted;
}
/////////////////////////////////////////////////////////////////////////
// TEST ERROR CLASS
public TestClass()
{
throw new Exception("im a custom error");
}
This works all right. With the try-catch, it catches the error as handled by the try-catch. Whereas, without the try-catch, it handles it in RunWorkerCompleted.
However, I really need to do these methods asynchronously (which is why I use ThreadPool) but the debugger always points at the exception. (it only crashes the program when I try it without the debugger)
// TEST ERROR CLASS
public TestClass()
{
ThreadPool.QueueUserWorkItem(delegate
{
throw new Exception("im a custom error");
}
}
I tried to rethrow the error using a try-catch statement (hoping it would pass the exception to the BackgroundWorker) but it didn't work.
Hope you can help me.
Thanks in advance.
You do not need to put code on the ThreadPool from the DoWork method. The BackgroundWorker will raise your _bgWorker_DoWork method on a ThreadPool thread automatically when you call RunWorkerAsync().
If you are trying to start SEVERAL MORE ThreadPool tasks from your background worker, then I suppose that could be a consideration, but in that case I would suggest using the TPL in .NET4 if at all possible...
http://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx
If you can not use TPL, then you must wrap your ThreadPool code in a TryCatch and put the Exception some place that can be accessed outside of that method.
For example add a internal static List<Exception> backgroundExceptions; member to your UI class, the background worker add's any caught exceptions to this list, and then you must investigate this list after your background work has completed to see if there were any Exceptions present.
This is essentially what the TPL is doing for you ... giving you a place to 'observe' exceptions that happened on the background thread, but it is still your responsibility to look for those Exceptions, either in the Task.Exception property, or by calling a method that will re-throw the Exception for you.

Catching exception of camera not avliable in C#

I have the following C# code to start camera feed with pressing of button:
private void bntStart_Click(object sender, EventArgs e)
{
webcam.Start();
}
In case that the computer doesn't have a camera installed i get auto MSG error:
"an error occured while capturing the video image. The video capture will now be termenated. Object refrence not set to an istance of object"
My goal is to add my own error msg for the user. I tried the following :
private void bntStart_Click(object sender, EventArgs e)
{
try
{
webcam.Start();
}
catch (NullReferenceException exception)
{
MessageBox.Show(exception.Message);
return;
}
}
but nothing happend. any ideas? I tried to debug but on run time it never gets to the catch... maybe wrong exception?
You are assuming webcam.Start() throws a NullReferenceException, which i believe is not the case, you can try to catch the Exception (it's the base exception, but generally not a good practice), inspect the exception type while debugging and catch the actual exception and do what is required
private void bntStart_Click(object sender, EventArgs e)
{
try
{
webcam.Start();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
return;
}
}
The Exception isn't catched, since it probably isn't a NullReferenceException, so that could mean webcam isn't equal to null.
You could try catching the error using Exception, change your code like this:
private void bntStart_Click(object sender, EventArgs e)
{
try
{
webcam.Start();
}
catch (Exception ex)
{
MessageBox.Show(String.Format("Something went wrong: {0}", ex.Message));
return; //Why is this return keyword here?
}
}
Why do you have return keyword in your code, while the method is at it's end already? Is this code made simple for posting here? I think it can be removed if so. Has nothing to do with your question tough.
It is possible to check for a NullReferenceException and an Exception, do this with following code:
private void bntStart_Click(object sender, EventArgs e)
{
try
{
webcam.Start();
}
catch(NullReferenceException nex)
{
MessageBox.Show(String.Format("NullReferenceException has been catched: {0}", ex.Message));
}
catch (Exception ex)
{
MessageBox.Show(String.Format("Something went wrong: {0}", ex.Message));
return; //Why is this return keyword here?
}
}
Is an exception even being thrown? You said you get an error message, but it's not clear from your description that this is actually an exception rather than the webcam library putting up its own messagebox.
If they're handling the error internally themselves and displaying a messagebox, you're out of luck - you can't catch what isn't being caught.
It seems like the error is caught and handled by the DLL itself. You're out of luck then. If there's no exception being thrown, there's nothing for you to catch. Unless you get access to the source code of the DLL, you're out of luck.

Catch child background threads within calling method in foreground thread

I want to call a method once by a specified interval (e.g. 3 seconds), but I have problem catching exception within the calling method (e.g. Start) thrown by the called method (timer_Elapsed)
Update
public void Start()
{
Timer timer = new Timer(PingPeriod); //System.Timers
try
{
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Enabled = true;
}
catch (Exception ex)
{
//I want to catch exception thrown by timer_Elapsed
}
//Logic here that keeps the method running
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
throw new exception("Catch this exception please");
}
Update:
Can anyone please confirm that the start() will NOT catch exception thrown from timer_Elapsed, or when trying to invoke timer_Elapsed if exception occurred.
Is there a better alternative, which can catch exception from a called method or get notified?
Any idea would be very much appreciated!
This just isn't possible, the Elapsed event handler runs later, well after your Start() method has exited. Furthermore, that event has the nasty habit of swallowing all exceptions without any diagnostic.
You'll need to handle exceptions within the event handler. Certainly not easy to do. Do consider using the System.Threading.Timer class instead. At least your program will terminate when the callback throws an exception.
This is not possible because the exception is thrown on a different execution context (thread) from the one that set up the timer.
You should handle any exceptions in your callback method. If you want your logic separated from your exception handling, simply create a separate method.
private void TimerElapsedCallback(object sender, ElapsedEventArgs e)
{
try
{
this.DoSomething();
}
catch (Exception ex)
{
// handle
}
}
private void DoSomething()
{
// logic goes here and can be agnostic of any exceptions it throws, if desired
}

BackgroundWorker dies unexpectedly

I have the following code:
public Mainform()
{
...
// scheduler
scheduler.DoWork += new System.ComponentModel.DoWorkEventHandler(scheduler_DoWork);
scheduler.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(scheduler_RunWorkerCompleted);
scheduler.WorkerReportsProgress = false;
scheduler.WorkerSupportsCancellation = true;
...
...
scheduler_DoWork(this, null);
scheduler.RunWorkerAsync(1000);
...
}
void scheduler_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
scheduler_Enabled = false;
CustomExceptionHandler eh = new CustomExceptionHandler();
eh.HandleUnhandledException(e.Error, "scheduler");
}
if(scheduler_Enabled)
{
scheduler.RunWorkerAsync(1000);
}
}
void scheduler_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
try
{
try
{
...do some stuff
}
catch(MyException ex)
{
ThreadSafeShowError();
}
finally
{}
...do more stuff
}
finally
{
if (e != null && e.Argument != null)
{
Thread.Sleep((int)e.Argument);
}
}
}
The backgroundworker thread died unexpectedly without any exception being thrown. I did not encounter this problem during development and it seems to be hard to reproduce. I suspected that maybe a cross thread exception was occurring when I am doing work in the scheduler_DoWork. I have tried to explicitly update the UI without checking if InvokeRequired and the thread continues to run without problems in a release build. How can this be? (Cross thread exception should occur) How can I determine what causes the thread to die? Any suggestions on how to figure out what is going wrong or how to debug this issue will be appreciated?
The RunWorkerCompleted event might not be fired on the UI Thread. If it is not, then the thread will end and your scheduler object will be garbage collected, which will make it seem like it just quit with no error. See this post for more details. Here and here are SO posts about this.
Your sample doesn't show enough code to determine what's going on but:
Maybe an exception is being thrown from ThreadSafeShowError? Why are you trying to show an error from the worker thread anyway - the conventional thing to do is to show e.Error if not null in the RunWorkerCompleted event handler.
To debug the issue try putting the following around all the code in your DoWork handler:
try
{
// do work
// log a trace statement here
}
catch(Exception ex)
{
// log exception, e.g. with System.Diagnostics.Debug.Write
throw;
}
finally
{
// log a trace statement here
}
You can do several things to increase the possibility of catching the exception:
Enable Managed Debugging Assistants for all exceptions in VS. To do that, go to Debug menu -> Exceptions..., and put a check mark next to "Managed Debugging Assistants" to enable all exceptions to be caught using debugger. Also, depending on the code you are executing, expand the CLR Exceptions node and select nodes of interest ("System" node, for example, will catch all exceptions from the System namespace in the debugger).
Obviously, put a try/catch block around your code, with some logging. You can also do something like this, if you are in real trouble:
try
{
// do stuff
}
catch (Exception ex)
{
#if DEBUG
// break only in DEBUG builds
System.Diagnostics.Debugger.Break();
#endif
// log the exception and throw
throw;
}
Put a try/catch with logging around your Application.Run(...) code in the Main() method. Exceptions do propagate up there sometimes, and this can catch them (even if not coming from this specific part of your code).
Add an Application.ThreadException event handler in your Main() method, before calling Application.Run, like this:
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
In Mainform, you never call scheduler.RunWorkerAsync, so your BackgroundWorker does not start at all.

Categories