在一个线程上连续运行任务

问题描述

我有几个线程(正在做服务器工作),需要将要在主线程上完成的工作排队(它们需要访问只能从主线程调用的API)。

使用Task系统对我来说很有意义,因为服务器线程可以生成使用此仅主线程的API的任务,将它们排队在主线程上运行并等待它们。主线程可以旋转并从ConcurrentQueue中弹出任务,然后在任务进入时运行它们。

从本质上讲,这与通常的模式有所不同,在该模式下,任务跨线程池并行运行。在这里,任务是从其他多个线程创建的,并排队等待在一个主线程上运行。

现在起皱纹:其中一些任务可能会产生子任务,这些子任务本身需要在主线程上运行。例如:

# On server thread:
Task taskA = new Task(async () => {
  Task taskB = new Task(() => Console.WriteLine("some sub work"));
  MainThreadWorkQueue.BeginInvoke(taskB);
  await taskB;
});
MainThreadWorkQueue.BeginInvoke(taskA);
await taskA;

这可能是因为顶层任务之一是使用库代码,而库代码本身需要在主线程上运行。

因此,我最终得到一个类似树的任务结构,其中根级任务需要阻止等待叶任务完成,但是根任务也在执行时动态创建这些叶任务。

问题是我不确定如何编写主线程代码。我在想类似的东西:

// Main thread:
while(true) {
  Task currentTask;
  while (MainThreadWorkQueue.TryDequeue(out currentTask)) {
    currentTask.Wait();
  }

  // Do other work
}

但是,这将在上面的taskA示例中陷入僵局,因为taskB被排队,但是taskA永远不会完成以允许taskB的工作开始。

理想情况下,我想执行以下操作:

// Main thread:
while(true) {
  Task currentTask;
  while (MainThreadWorkQueue.TryDequeue(out currentTask)) {
    currentTask.RunUntilFinishedOrBlocked();
    if (currentTask.IsBlockedOnOtherTask) {
      MainThreadWorkQueue.Enqueue(currentTask)
    }
  }

  // Do other work
}

是否有一种方法可以运行任务,直到该任务被其他任务阻止为止?还是解决该问题的另一种方法?

解决方法

You should never use the Task constructor。它的用例几乎为零。

在您的情况下,您要查找的类型不是Task;这是一个委托人:

我正在尝试使用任务来代表工作单位

Task是错误的类型。听起来更像Func<Task>

我想先运行taskA,直到它阻塞,然后再运行taskB,然后继续运行taskA。

在这种情况下,应使用单线程的SynchronizationContext。您可以通过在UI线程上运行这些任务,也可以在AsyncContext之类的文件中运行它们来完成此任务。 AsyncContext有一个内置的工作队列,直到完成为止。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...