C# 为什么如果我尝试使用CancellationToken.Cancel()停止一个任务,那么实际的任务会在task.Wait()上被阻塞?

C# 为什么如果我尝试使用CancellationToken.Cancel()停止一个任务,那么实际的任务会在task.Wait()上被阻塞?,c#,task,cancellationtokensource,C#,Task,Cancellationtokensource,我正试图在C#中实现一个任务取消,下面是我的MSDN提供的示例。 我有一个Windows窗体应用程序,其中有一个图形显示来自外部设备的数据,还有一个启动/停止按钮。这是按钮内部的代码,或多或少: if (drawGraph_task == null) { cts = new System.Threading.CancellationTokenSource(); token = cts.Token; drawGraph_task = new Task(() =>

我正试图在C#中实现一个任务取消,下面是我的MSDN提供的示例。 我有一个Windows窗体应用程序,其中有一个图形显示来自外部设备的数据,还有一个启动/停止按钮。这是按钮内部的代码,或多或少:

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";
    }
}
为什么代码在drawGraph_task.Wait()调用时仍然死机? 我试图在任务中使用token.throwIfCancellationRequested(),但有时我也有同样的效果,有时我的catch无法捕获异常。我做错了什么? 为了完整性,x和y的计算包括:

  • MathNet插值库
  • 调用内部生成的库进行特定于协议的通信,以等待事件(它总是启动的,因此这不是问题的根源)

Task.Wait()是同步的。如果由于调用Invoke()而可以返回此方法,则会出现死锁。当达到stucked状态时,使用调试器检查调用堆栈的状态

如果(token.IsCancellationRequested)返回,循环是否到达
语句?可能任务在调用外部方法时遇到问题……您正在调用
drawGraph_task.Wait(),大概在UI线程上。同时,您的独立任务正在尝试做的大量工作是通过
调用
尝试返回UI线程。除非你非常幸运,否则你不太可能在正确的时候调用
Cancel
,这样你的工作人员就要查询令牌了。基本上,如果你手动创建
任务
,然后不得不编写大量基于
调用
的代码,你可能采取了错误的方法来分割你的工作。在这里,任务中的每一行代码,除了取消位,实际上都需要在UI线程上运行。单独运行的好处是什么?等待是阻塞,您试图从哪里调用
。取消
,在代码中看不到它。@tigerswithguitars-
取消
被称为
等待
上方的4行。