Search code examples
c#taskcancellationtokensource

Why if I try to stop a task using CancellationToken.Cancel() then the actual task get stucked on Task.Wait()?


I'm trying to implement a task cancellation in C#, following the examples provided my MSDN. I have a Windows Form application with a Graph showing data coming from external devices and a start/stop button. That's the code, more or less, inside the button:

if (drawGraph_task == null)
{
    cts = new System.Threading.CancellationTokenSource();
    token = cts.Token;
    drawGraph_task = new Task(() => 
    {
        this.Invoke(new InvokeDelegate(this.myChart.Series[0].Points.Clear));

        while (true)
        {
            // get x and y from device using external lib
            this.Invoke(new addPointXYDelegate(this.myChart.Series[0].Points.AddXY), new object[] { x, y });
            this.Invoke(new InvokeDelegate(this.chart_pressure.Update)); // update graph

            if (token.IsCancellationRequested)
            {
                return;
            }

        }
    }, token);
    this.button_main_start.Text = "Stop";
    drawGraph_task.Start();                
}
else
{
    cts.Cancel();

    try
    {
        drawGraph_task.Wait();
    }
    catch (AggregateException ae)
    {
        // do nothing
    }
    finally
    {
        cts.Dispose();
        drawGraph_task.Dispose();
        drawGraph_task = null;
        this.button_main_start.Text = "Restart";
    }
}

Why the code remains stucked at the drawGraph_task.Wait() call? I tried to use the token.throwIfCancellationRequested() inside the task, but sometimed I have the same effect, sometimes the exception is not catched by my catch. What am I doing wrong? For completeness, calculation of x and y involves:

  • MathNet Interpolate library
  • calls to a in-house made library for protocol specific communication that made to wait for an event (it's been always launched, so this is not the source of the problem)

Solution

  • Task.Wait() is synchronous. If it happens that due to an Invoke() call you can return to this method, you get a deadlock. Use the debugger to inspect the state of your callstack when you have reached the stucked state.