【问题标题】:Can the threadpool thread that's waiting on a set of Tasks end up serving one of those other Tasks?等待一组任务的线程池线程最终能否为其他任务之一提供服务?
【发布时间】:2018-05-22 17:06:00
【问题描述】:

假设您有一组像这样创建的子任务:

var childTasks = new List<Task<ResultType>>();
for (var i = 0; i < Count; i++)
{
    var childTask = new Task<ResultType>(() => {  logic here  });
    childTasks.Add(childTask);
    childTask.Start();
}

如果某个逻辑操作“A”本身是作为一个任务启动的,并且在我们命名为“A”的线程池线程中运行,并且它调用Task.WaitAll(childTasks.Select(x =&gt; (Task)x).ToArray()); //cast Task&lt;T&gt; to Task and make array as required by Task.WaitAll,那么线程池线程“A”是否有可能是在 WaitAll 操作期间返回到池中并用于服务其中一个子任务?换句话说,childTask 是否有可能最终在调用任务使用的同一线程池线程上运行?

或者,WaitAll 会阻塞当前线程并阻止它返回池中吗?

【问题讨论】:

  • Wait*()s 正在阻止呼叫。
  • 我们看到一个问题,即启动另一个任务的任务有线程串扰,但是当使用调用任务的 new Thread() 时,没有串扰。我们看到存储在 Thread.Name(即 Guid.NewGuid().ToString())上的项以检索调用线程的值。就好像子任务以某种方式在调用者的线程上运行并处理它拥有的对象,这样当返回调用线程时(即 WaitAll 返回),与其线程名称关联的对象消失了,可能是由子任务处理在某些时候得到了相同的线程。
  • 在极少数情况下(尤其是在 VS 扩展中),您可以从 COM 事件循环中获得重入。

标签: .net multithreading threadpool


【解决方案1】:

A 不会被退回。您的代码仍在堆栈中。基本上是这样的。

但是可以发生任务内联。每当您等待任务时,TPL 都可以直接在当前线程上执行该任务。这是一个效率优化。在我看来,这也是一个令人震惊的设计错误。这意味着等待任何任务实际上可以在此时执行任意代码。这是非常不可预测的。

childTask.Start() 不会这样做,因为它不等待,但所有等待函数都可以这样做。它是可怕的。见https://github.com/dotnet/corefx/issues/2454

【讨论】:

    猜你喜欢
    • 2015-07-13
    • 2011-06-02
    • 2019-09-18
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-08
    相关资源
    最近更新 更多