Search code examples
c#backgroundworkercancellation

Best way to cancel long running process inside backgroundworker


What is the best solution to quickly cancel long running processes inside background worker? For example, we have such situation:

        private void DoWork(object sender, DoWorkEventArgs e)
        {
            ...

            for (int i = 0; i < items; i++)
            {
                if (_worker.CancellationPending == true)
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    VeryLongRunningProcess();
                }
            }
        }
        
        private void VeryLongRunningProcess()
        {
            var a = Test();
            var b = Test2();
            Thread.Sleep(5000);
            var c = Test3();
        }

In such case, VeryLongRunningProcess() will be not finished on pressing cancel until he finished everything inside his body.

What to do in such cases?

I tried to pass (BackgroundWorker)sender to VeryLongRunningProcess() as param and inside this method check for CancellationPending, but i dont know is this correct way or not


Solution

  • If the problem is isolated your VeryLongRunningProcess from classes like the worker, you can use a Func as a parameter and leave outside your method the worker access

    private void VeryLongRunningProcess(Func<bool> isCancelled)
    {
        var a = Test();
    
        if (isCancelled())
        {
            return;
        }
    
        var b = Test2();
    
        if (isCancelled())
        {
            return;
        }
    
        Thread.Sleep(5000);
        var c = Test3();
    }
    

    Inside your method, you may check if you must cancel the operation as many times you need. And you can use the Func as a parameter in other methods like Test1, Test2... if any of them takes long time to finish.

    Then, you invoke your method in this form:

    VeryLongRunningProcess(() => _worker.CancellationPending);
    

    As other people comment, maybe interesting use async/await.

    UPDATE

    Another way to do if you want choose the use or not of the cancellation:

    private void VeryLongRunningProcess(Func<bool> isCancelled = null)
    {
        var a = Test();
    
        // Or: isCancelled != null && isCancelled()
        if (isCancelled?.Invoke() ?? false)
        {
            return;
        }
    
        // ...
    }