How close BackgroundWorker thread when application is deactivated?

10,043

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 the CancelAsync 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?

Share:
10,043
Aram Gevorgyan
Author by

Aram Gevorgyan

Updated on June 04, 2022

Comments

  • Aram Gevorgyan
    Aram Gevorgyan almost 2 years

    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 = 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
    Aram Gevorgyan over 12 years
    I edit my code. Plz look here is my whole code. And yes I set WorkerSupportsCancellation true/
  • thumbmunkeys
    thumbmunkeys over 12 years
    as 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
    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
    Aram Gevorgyan over 12 years
    remove 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
    Aram Gevorgyan over 12 years
    Where I must check CancelationPending ?
  • thumbmunkeys
    thumbmunkeys over 12 years
    In bw_DoWork remove the CancelAsync. 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
    Aram Gevorgyan over 12 years
    Earlier 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
    Aram Gevorgyan over 12 years
    And 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
    A9S6 over 12 years
    You 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
    Aram Gevorgyan over 12 years
    Ok, 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.