【问题标题】:Missing CancellationToken.WaitHandle.Set() or how to indicate that a task is complete缺少 CancellationToken.WaitHandle.Set() 或如何指示任务已完成
【发布时间】:2023-09-26 13:40:01
【问题描述】:

我有一个函数可以定期检查网页(使用 REST),然后等待最终响应,如果它得到“非最终”响应,它会再次尝试。

void PeriodicallyCheckSomething()
{
    Task.Run(() => {
        var isTaskComplete = false;
        while (!isTaskComplete)
        {
            CancellationToken.WaitHandle.Wait(5000);
            if (isTaskComplete || CancellationToken.IsCancellationRequested)
                return;

            CheckProgress((isComplete) => {
                isTaskComplete = isComplete;
                CancellationToken.WaitHandle.Set(); // <== can't do this
            });
        }
    });
}

// CheckProgress - exit's immediately, we use updateStatus to report the result

void CheckProgress(Action<bool> updateStatus)
{
    MakeWebRequest((data) => {
        var isComplete = (data.Result == 999);
        updateStatus(isComplete);
    });
}

我想彻底退出任务。当我得到结果时,我设置了 isTaskComplete 标志,但任务已经处于等待状态。

我想“设置”Waithandle 以便任务立即退出。但是 CancellationToken.Waihandle 没有 Set 函数。

有没有更好的等待方式...既支持任务取消,又支持使用 Set 之类的东西发出信号?

【问题讨论】:

  • 很明显你的代码是不正确的,但同样的优点是不清楚你想要什么最终结果。例如,除了检查取消令牌之外,您为什么还要对它做任何事情?
  • CancellationTokenSource.Cancel() 在此函数之外被调用。例如,如果有人点击 UI 上的取消按钮。
  • 是的,这就是为什么您唯一应该做的就是检查它。
  • 您能澄清一下您要解决的问题吗?第一种方法中的代码毫无意义……我所看到的只是一个无限循环。你在尝试什么行为?伪代码会很好,甚至只是简单的英语。
  • 第一个方法循环直到 isTaskComplete 为真...这将被 CheckProgress 函数中的 updateStatus 回调设置为真。

标签: c# task cancellation-token


【解决方案1】:

使用Task.Delay 等待 5000 毫秒。您可以通过其中一个重载将CancellationToken 传递给Delay 方法。我没有看到您需要跟踪完成与取消概念的原因。您只是希望任务无论如何都结束。

【讨论】:

    【解决方案2】:

    我认为您需要做的是启动一个任务,为其提供取消令牌并在任务“外部”执行等待。即您的 PeriodicallyCheckSomething() 方法可以从其他地方重新标记为 async 和 Task.Run 。然后其他地方可以执行等待,等等。只是我的 2c。 祝你好运

    【讨论】:

      【解决方案3】:

      我所做的是让 MakeWebRequest 成为一个阻塞函数。

      void PeriodicallyCheckSomething()
      {
          Task.Run(() => {
              var isTaskComplete = false;
              while (!isTaskComplete)
              {
                  CancellationToken.WaitHandle.Wait(5000);
                  if (CancellationToken.IsCancellationRequested)
                      return;
      
                  isTaskComplete = CheckProgress();
              }
          });
      }
      
      bool CheckProgress()
      {
          var data = MakeWebRequest();
          return (data.Result == 999);
      }
      

      【讨论】: