I create thread with BackgroundWorker
, and in the loop I check every time if CancellationPending
is true or not, like this:
public MainPage()
{
InitializeComponent();
bw = new BackgroundWorker();
bw.WorkerReportsProgress = tr开发者_StackOverflow中文版ue;
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?
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.
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.
`
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.
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?
精彩评论