c# - 如何正确启动和取消任务。

标签 c# multithreading asynchronous async-await task

我似乎无法思考如何正确地开始和取消任务。我更改了我的代码以更容易理解我的问题并将其粘贴在下面(我还添加了一些评论)。 SubscribeToReport 方法首先被调用 - 它包含一个 await runReportTask 根据我的理解,它只会启动 runReportTask 方法,等待它完成执行,然后继续执行出现在 await 之后的代码。

runReportTask 中,我创建了一个 CancellationTokenSource 并使用 Task.Factory.StartNew() 开始了一个新任务。在任务内部,有一个 while 循环,只要任务没有被取消,它就会执行处理。根据我的理解,如果 cancellationToken.IsCancellationRequested 永远为真,我的 while 循环中的 else 将运行并且任务将停止。之后,我希望 SubscribeToReport() 继续执行 - 这不会发生,而且当我调用 cancellationTokenSource.Cancel() 时,我的代码似乎什么也没做> 在 StopReportTask() 中。我究竟做错了什么?我已经这样做了一段时间,但我似乎无法理解这应该如何工作。

private async static void SubscribeToReport()
{
    Console.WriteLine("Waiting for task to finish or cancel...");

    await runReportTask();

    Console.WriteLine("Task has finished or was canceled."); // THIS LINE NEVER EXECUTES
}

private static CancellationTokenSource cancellationTokenSource;
private static CancellationToken cancellationToken;
private bool moreToDo = true;
private static Task runReportTask()
{
    cancellationTokenSource = new CancellationTokenSource();
    cancellationToken = cancellationTokenSource.Token;

    return Task.Factory.StartNew(() =>
    {
        // Were we already canceled?
        cancellationToken.ThrowIfCancellationRequested();

        while(moreToDo == true)
        {
            if(!cancellationToken.IsCancellationRequested)
            {
                // Do important code here
            }
            else{
                Console.WriteLine("Task canceled."); // THIS LINE NEVER EXECUTES WHEN CALLING StopReportTask() below
                cancellationToken.ThrowIfCancellationRequested();
                break;
            }
        }

    }, cancellationToken);
}

// This method is called from another source file
private void StopReportTask()
{
    Console.WriteLine("Stopping report task...");

    cancellationTokenSource.Cancel();
}

最佳答案

it contains an await runReportTask which from my understanding will just start the runReportTask method, wait for it to complete execution, then resume executing the code that appear after the await.

代码:

await runReportTask();

就像这样的代码:

var task = runReportTask();
await task;

因此,明确地说,启动任务运行的是方法调用await 只是(异步地)等待它完成。

同样重要的是要注意 await 是一个异步等待。这意味着它会暂停方法的执行并返回。因此,就您的调用代码而言,SubscribeToReport 已完成执行。

(这是 problems of async void 之一;它不容易使用 - 调用代码不知道它何时完成)。

Inside runReportTask I create a CancellationTokenSource and start a new task using Task.Factory.StartNew().

作为旁注,您应该使用 Task.RunTask.Factory.StartNew is a low-level API with dangerous default settings .

it doesn't ever seem like my code does anything when I call cancellationTokenSource.Cancel() in StopReportTask()

它可能是一个不同的 cancellationTokenSource 实例。

您可以试试这个,作为测试 - 不过我不确定这是否是您想要的语义(它会导致 runReportTask 取消之前的尝试):

private static CancellationTokenSource cancellationTokenSource;
private static readonly object _mutex = new object();
private bool moreToDo = true;
private static Task runReportTask()
{
  CancellationTokenSource oldCts, currentCts;
  lock (_mutex)
  {
    oldCts = cancellationTokenSource;
    currentCts = cancellationTokenSource = new CancellationTokenSource();
  }
  if (oldCts != null)
    oldCts.Cancel();
  var cancellationToken = currentCts.Token;
  ...
}

关于c# - 如何正确启动和取消任务。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43245350/

相关文章:

c# - 在 C# 中进行线程工作的最佳方法是什么?

javascript - 如何将参数传递给 onQuerySucceeded 函数

JavaScript 异步函数的困境

c# - 在 INSTEAD OF INSERT 中设置列​​的值

c# - 从 LinkedList<T> 快速删除项目

c++ - Boost:阻塞直到队列有另一个项目

java - 在 java servlet 应用程序中执行异步数据库任务

c# - 有生存时间启动外部流程

c# - ideviceinfo.exe 返回 Lockdownd 错误代码 -2

windows - Boost.test 和对 Boost.thread 的依赖?