How close BackgroundWorker thread when application is deactivated?
Solution 1
Did you set the BackgroundWorker
to be cancelable?
var bg= new BackgroundWorker();
bg.WorkerSupportsCancellation = true;
From the documentation:
Set the
WorkerSupportsCancellation
property to true if you want the BackgroundWorker to support cancellation. When this property is true, you can call theCancelAsync
method to interrupt a background operation.
Also your code seems to be wrong, you should call the CancelAsync()
outside of your thread code, this will set the CancellationPending
flag that you can use to exit the loop.
Although I'm not 100% sure as I don't know where the bw
variable is coming from.
`
Solution 2
When an app is deactivated, every thread other than the main UI thread will throw a ThreadAbortException as soon as it becomes active. This appears to be "by design" as a way of forcing apps to quickly stop what they are doing. Threads can catch the ThreadAbortException and wrap up what they are doing, but be aware that the ThreadAbortException will be automatically raised again at the end of the catch block. Any code in a finally block will also be executed.
For your specific issue, there's no reason to attempt to cancel the BackgroundWorker when the app is deactivated because the ThreadAbortException will occur and will effectively stop the background worker. If you want to do something to clean up when this occurs, you catch the ThreadAbortException in bw_DoWork, do what you need to do, and then let it die.
To get it to start again after activation, you would have to restart the background worker, just like you did the first time the app ran.
Solution 3
You should check the CancellationPending flag in your worker method and exit gracefully if the flag is set.
What is the condition for job cancellation? Cancel Button Click? Then you should put the CancelAsync(...) call there. It will set the CancellationPending flag for you which you are already checking in your code, avoiding the need for something like a ResetEvent object.
Solution 4
I want to add one clarifying point to the answers above, based on my own observations. Background threads survive deactivation / activation when the instance is preserved.
I had code that looked like this:
private void Application_Activated(object sender, ActivatedEventArgs e)
{
if (e.IsApplicationInstancePreserved)
{
Log.write("Activating, instance preserved");
// restart long-running network requests
startBackground();
}
else // start over again
{
AppSettings.init();
Log.write("Activating, rehydrating" );
startBackground();
}
}
I also logged the hashcode of the BackgroundWorker
object when it executed. What I saw was that every time I got an "Activating, instance preserved" message, I got an additional BackgroundWorker
running.
Based on this it seems more likely accurate to say that threads are aborted on tombstoning, not on deactivation?
Aram Gevorgyan
Updated on June 04, 2022Comments
-
Aram Gevorgyan almost 2 years
I create thread with
BackgroundWorker
, and in the loop I check every time ifCancellationPending
is true or not, like this:public MainPage() { InitializeComponent(); bw = new BackgroundWorker(); bw.WorkerReportsProgress = true; bw.WorkerSupportsCancellation = true; bw.DoWork += new DoWorkEventHandler(bw_DoWork); bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); } private void ButtonStart_Click(object sender, RoutedEventArgs e) { if (bw.IsBusy != true) { bw.RunWorkerAsync(); } } private void ButtonCancel_Click(object sender, RoutedEventArgs e) { if (bw.WorkerSupportsCancellation) { bw.CancelAsync(); } } private void bw_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker; for (int i = 1; i <= 100; i++) { Debug.WriteLine("The tread is working"); if (worker.CancellationPending) { e.Cancel = true; bw.CancelAsync(); break; } else { System.Threading.Thread.Sleep(500); worker.ReportProgress(i); } } } private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) { tbProgress.Text = "Canceled"; } else if (e.Error != null) { tbProgress.Text = "Error: " + e.Error.Message; } else { tbProgress.Text = "Done"; } } private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) { tbProgress.Text = e.ProgressPercentage.ToString() + "%"; }
When application is deactivated, the thread wasn't closed, it is aborted and the exception occurs. How close threads with
BackgroundWorker
when application is deactivated? -
Aram Gevorgyan over 12 yearsI edit my code. Plz look here is my whole code. And yes I set WorkerSupportsCancellation true/
-
thumbmunkeys over 12 yearsas I said, remove the line
bw.CancelAsync()
from your do_Work method. It would be also helpful if you post which exception you get -
Aram Gevorgyan over 12 years@9S6 No the condition for CancelationPending is application deactivated state. I want BW to close thred when application is thombstoned and continue thread when application is activated.
-
Aram Gevorgyan over 12 yearsremove where? And when I enabled thombstone in debug in project properties I get exception : A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll A first chance exception of type 'System.Threading.ThreadAbortException' occurred in System.dll
-
Aram Gevorgyan over 12 yearsWhere I must check CancelationPending ?
-
thumbmunkeys over 12 yearsIn
bw_DoWork
remove theCancelAsync
. At this point the worker is already canceled so no need to cancel it again. Also a first chance exception does not need to be necessarily a problem. -
Aram Gevorgyan over 12 yearsEarlier it was removed I add it later, but nothing changed. It's problem bacause I want my thread to continue working when application activated, but it isn't working and when I star it manually it begin working from zero.
-
Aram Gevorgyan over 12 yearsAnd I want my thread to work when application is working and stop when application is thombstoned. no matter it is deactivated from this page or another.
-
A9S6 over 12 yearsYou should call CancelAysnc(...) when your app is deactivated and start the BackgroundWorker again when the app is activated. Calling CancelAsync(...) will set the CancellationPending flag. You are already checking that flag in your worker method --just remove the call to CancelAsync(...) from there.
-
Aram Gevorgyan over 12 yearsOk, but how in my app.xaml I can get element defined in page.xaml? And I want to close thread in the page not in application level.