Search code examples
c#cancellation

Run method Safe cancellation?


I want to call a function in a different thread than my GUI.

I used the below code to trigger the function:

private void button1_Click(object sender, EventArgs e)
{
    tokensource = new CancellationTokenSource();
    var token = tokensource.Token;
    Task.Run(()=>foo() , token);
}

private void foo()
{
    // Uses some resources
}

private void button2_Click(object sender, EventArgs e)
{
    tokenSource.Cancel();
}

How can I safely close the occupied resources in foo() when the task is cancelled?


Solution

  • You need to pass the token to the function as well. The cancellation token passed to Task.Run won't abort an already running task, it will prevent a scheduled task from running.

    Inside foo, you can check the token for cancellation and return, or throw an exception. You can use a using block to dispose resources safely. Eg:

    private void foo(CancellationToken token)
    {
        using(var reader=new StreamReader(somePath)
        {
                string line;
                // Read the line if no cancellation was requested
                while (!token.IsCancellationRequested && (line = sr.ReadLine()) != null) 
                {
                    Console.WriteLine(line);
                }
        }
    }
    

    This code reads a line only if cancellation wasn't requested and returns quietly otherwise

    You can also throw an OperationCancelledException by calling CancellationToken.ThrowIfCancellationRequested

    private void foo(CancellationToken token)
    {
        using(var reader=new StreamReader(somePath)
        {
                string line;
                // Read the line if no cancellation was requested
                while ((line = sr.ReadLine()) != null) 
                {
                    token.ThrowIfCancellationRequested();
                    Console.WriteLine(line);
                }
        }
    }
    

    This will throw an exception that will be raised in the calling code when the task's result is retrieved, eg when using await Task.Run(..) or Task.Run(..).Wait()