I have two background threads and a thread to handle minimization running on my WinForms Application. When the program closes, I use this method.
private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
if(labelsUpdaterThread.IsAlive == true)
labelsUpdaterThread.Abort();
if(printNotifyThread.IsAlive == true)
printNotifyThread.Abort();
if(minimizeThread.IsAlive == true)
minimizeThread.Abort();
}
labelsUpdaterThread and printNotifyThread run all the time. MinimizeThread, as you might guess, only runs when the parent form is minimized. Here's my problem:
When the thread.abort methods are called in my above method, the "X" on the top right of my MdiParent form doesn't do anything. Clicking it has no effect.
When the thread.abort methods are NOT called in my above method, closing the MdiParent will sometimes throw exceptions because the Threads are still trying to access resources on the MdiParent that are no longer available, even though they are background threads!
I'm unsure as to why this is happening, doesn't make much sense to me. Thanks in advance for any help!
I agree with Paul Alexander's answer in that you should never call Thread.Abort
, it's a horrible way to handle synchronization.
Additionally, you have a horrible separation of concerns here. The threads should not access resources in the form directly. There should be some sort of abstraction/shared-state in between, which is modified and read by both sides (the thread and the form, so make sure to make the instance thread-safe).
That said, if you couldn't make those changes then in the Close method, call the Thread.Abort
methods in another thread with a try/catch statement around each. Log the error(s) somewhere at least.
In performing the calls to Thread.Abort
on another thread, you don't block the UI thread, as the calls to Thread.Abort
are not guaranteed to be instantaneous, and blocking the UI thread will cause the X to be greyed out while the UI thread cannot process Windows Messages (it also helps to guide you to a better separation of concerns).
However, you should move to abstract out the resources that are shared between the form and the thread, as well as provide a proper cancellation mechanism.
If you abstract out the resources to a class that shares the state, then your form doesn't have to do anything on close, the thread call stacks have a reference to the object that has the state and you can then call abort on those threads without worrying about the form and the threads sharing anything.
From there, you can then introduce a proper cooperative cancellation mechanism (cooperative cancellation, which Task supports in .NET 4.0, if that's available to you).