Search code examples
c#multithreadingbackgroundworker

Quitting BackgroundWorker using flag


Imagine I Have such code:

 private bool flag = false;
 public SomeClass()
 {
     public void setup()
    {
        worker = new BackgroundWorker();
        worker.DoWork += worker_DoWork;

        if(!worker.IsBusy)
            worker.RunWorkerAsync();
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        if(flag == true)
          return;
        //whatever You want the background thread to do...
        SomeClass.SomeStaticMethodWhichHasLoopInside();
    }
}

When user clicks Exit button in my application I can set flag=true inside - is this the right way to stop the thread started by BackgroundWorker? I want to do this only when application wants to quit - so that I stop the thread. Or it will be automatically killed?


Solution

  • No. Don't do that. It will not work as expected. Your flag field isn't even declared as volatile; it is possible that true value of the field isn't flushed to the memory yet. Other thread will still see the flag to be false because it caches its own copy of the value and your BackgroundWorker may never end.

    Instead, just call BackgroundWorker.CancelAsync and check for BackgroundWorker.CancellationPending boolean inside the DoWork event handler.

    private void OnExit(..)
    {
        worker.CancelAsync();
    }
    

    So your DoWork method will become

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        while(!worker.CancellationPending)
        {
            //whatever You want the background thread to do...
        }
    }
    

    If you don't have a loop, you need to check CancellationPending property time to time.

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        if(worker.CancellationPending)
            return;
        //Do something..
        if(worker.CancellationPending)
            return;
        //Do some other thing..
        if(worker.CancellationPending)
            return;
        //Do something else..
    }
    

    I want to do this only when application wants to quit - so that I stop the thread. Or it will be automatically killed?

    It will be killed automatically by the CLR since the thread is a Background Thread. But, don't rely on this fact because we don't know what your thread will be executing at the time CLR kills the thread. For example, it might have been writing a file in which case you'd be left with the corrupted file.

    Consequences can be even worse, so it is always recommended to stop your threads yourself gracefully.

    Question asked in comments: How can I cancel when the loop is in some other method?

    It seems you're using .Net4.5. You can take advantage of CancellationTokenSource and CancellationToken. Also you may consider using TPL and async-await features which will make your life a lot easier.

    private CancellationTokenSource tokenSource = new CancellationTokenSource();
    
    private void OnExit(..)
    {
        tokenSource.Cancel();
    }
    
    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        //whatever You want the background thread to do...
        SomeClass.SomeStaticMethodWhichHasLoopInside(tokenSource.Token);
    }
    
    class SomeClass
    {
        public static void SomeStaticMethodWhichHasLoopInside(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                //Do something
            }
        }
    }