c#-在任务执行代码时尝试处置任务

c#-在任务执行代码时尝试处置任务,c#,C#,当“worker”正在执行一段代码时,我正在关闭整个窗口,我想在关闭该窗口时处理它,因为它正在完成它的代码 Task worker = Task.Factory.StartNew(new Action(() => { // some code here } 不幸的是,当我在Close()中调用worker.Dispose()时,出现了一个异常: 只有在任务处于完成状态时,才能对其进行处理 (RANTO完成、故障或取消) 有什么建议可以在它工作时处理吗?尝试使用取消令牌 var

当“worker”正在执行一段代码时,我正在关闭整个窗口,我想在关闭该窗口时处理它,因为它正在完成它的代码

Task  worker = Task.Factory.StartNew(new Action(() =>
{ 
    // some code here
}
不幸的是,当我在
Close()
中调用
worker.Dispose()
时,出现了一个异常:

只有在任务处于完成状态时,才能对其进行处理 (RANTO完成、故障或取消)


有什么建议可以在它工作时处理吗?

尝试使用取消令牌

var cancellationTokenSource = new CancellationTokenSource();
var t = Task.Factory.StartNew(() =>
        {
            // Your code here 
        }, cancellationTokenSource.Token).ContinueWith(task =>
          {
              if (!task.IsCompleted || task.IsFaulted)
              {
                  // log error
              }
          }, cancellationTokenSource.Token);

将cancellationTokenSource放在手边,并在关闭()时取消它。

您需要编写代码,以便您的任务将接受取消令牌。这基本上只是一个可以由任务中的代码检查的标志,如果更新,您将提供要处理的逻辑,让任务的逻辑安全地处理如何终止其执行,而不是简单地在未知状态下停止。在LinqPad中运行以下示例代码应该可以为您提供一个合理的示例:

void Main()
{
    var form = new Form();
    var label = new Label(){Text = string.Format("{0:HH:mm:ss}", DateTime.UtcNow), AutoSize = true};
    form.Controls.Add(label);
    var taskController = new CancellationTokenSource(); 
    var token = taskController.Token;
    var task = Task.Run(() => 
    {
        for (var i=0; i<100; i++)
        {
            var text = string.Format("{0:HH:mm:ss}", DateTime.UtcNow);
            Console.WriteLine(text); //lets us see what the task does after the form's closed
            label.Text = text;
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("Cancellation Token Detected");
                break;
            }
            Thread.Sleep(1000);
        }
    }, token);
    form.FormClosed += new FormClosedEventHandler(
        (object sender, FormClosedEventArgs e) => 
        {taskController.Cancel();}
    );
    form.Show();
}
  • 从该源获取令牌

    var token = taskController.Token;
    
  • 运行任务,传递对令牌的引用

    var task = Task.Run(() => 
    {
        //...
        , token
    }
    
  • 在任务中添加逻辑,以在适当的点检查此令牌的状态,并适当地处理它

    if (token.IsCancellationRequested)
    {
        Console.WriteLine("Cancellation Token Detected");
        break;
    }
    
  • 添加逻辑以在希望取消任务时调用
    Cancel
    方法。在上面的代码中,我将其放在表单的FormClosed事件处理程序的逻辑下:

    taskController.Cancel();
    
  • 有关取消任务的详细说明/相关方法,请参阅

    旁注 在上面的例子中,我有点懒。循环的每次迭代我检查取消令牌;但是(如果没有取消)在循环之前等待1秒。由于cancel逻辑只有在计算
    if
    语句时才起作用,这意味着我们必须等待1秒,以使取消生效,这不是很好;如果延迟时间更长(例如5分钟),可能会非常痛苦。这里概述了一种解决方案:

    i、 e.更换

    if (token.IsCancellationRequested)
    {
        Console.WriteLine("Cancellation Token Detected");
        break;
    }
    Thread.Sleep(1000);
    


    有关
    WaitOne
    方法的文档,请参阅。

    您需要先取消
    任务执行。阅读有关任务取消的详细信息。您不需要。先取消它。这就是为什么任务接受
    CancellationToken
    s(并且显式地处理任务很少是必要的或有用的)。真的很有帮助!伟大的我真的很感激!您可以使用
    wait Task.Delay(1000,令牌),而不是WaitHandle
    
    if (token.IsCancellationRequested)
    {
        Console.WriteLine("Cancellation Token Detected");
        break;
    }
    Thread.Sleep(1000);
    
    if (token.IsCancellationRequested)
    {
        Console.WriteLine("Cancellation Token Detected");
        break;
    }
    token.WaitHandle.WaitOne(1000);