【问题标题】:System.Threading.Tasks not obeying start rules?System.Threading.Tasks 不遵守启动规则?
【发布时间】:2011-09-30 00:08:37
【问题描述】:

重写:我已将问题精简为包含示例代码而不是指向它的链接以及结果和问题,因为周围的信息似乎引起了混乱。

问题:为什么任务似乎没有开始就开始了?

这是来自Microsoft Website 任务的一段示例代码。它被描述为创建一个未启动的任务,创建第二个已启动的任务并等待它完成,然后启动第一个任务,最后在主线程中同步启动第三个任务。

这里是示例代码的未注释版本:

using System;
using System.Threading;
using System.Threading.Tasks;

class StartNewDemo
{
    static void Main()
    {
        Action<object> action = (object obj) =>
        {
            Console.WriteLine("Task={0}, obj={1}, Thread={2}", Task.CurrentId, obj.ToString(), Thread.CurrentThread.ManagedThreadId);
        };

        Task t1 = new Task(action, "alpha");

        Task t2 = Task.Factory.StartNew(action, "beta");

        t2.Wait();

        t1.Start();

        Console.WriteLine("t1 has been launched. (Main Thread={0})", Thread.CurrentThread.ManagedThreadId);

        t1.Wait();

        Task t3 = new Task(action, "gamma");

        t3.RunSynchronously();

        t3.Wait();
    }
}

结果如下:

Task=1, obj=beta, Thread=3
t1 has been launched. (Main Thread=1)
Task=2, obj=alpha, Thread=3
Task=3, obj=gamma, Thread=1

从描述任务 1,它是 Beta,应该只在任务 2 完成后运行,以便主线程可以继续。从这个输出来看,情况似乎并非如此。我还进行了第二次测试运行,将滴答计数显示到操作对象中并收到了这个,确认 Task1 确实在 Task2 完成之前开始。

Task=1, obj=beta, Thread=3 (634529151744201906)
t1 has been launched. (Main Thread=1)
Task=2, obj=alpha, Thread=3 (634529151744221908)
Task=3, obj=gamma, Thread=1 (634529151744221908)

我不想在这里做任何花哨的事情,我只是想解释一下为什么 Task1 (obj=beta) 在得到执行指令之前显然正在执行。

【问题讨论】:

  • “我正在开发的软件需要仔细控制在工作流程的特定阶段点亮多少或哪些内核”-您能解释一下原因吗?如果代码适合多线程,为什么需要特定的核心数?
  • 从问题中删除了该行,因为它与问题无关。我想提供了太多的背景信息。

标签: c# .net multithreading task


【解决方案1】:
Task=1, obj=beta, Thread=3

Task=1 在这里有点误导,因为这实际上是示例代码中的 t2。您可以看到这一点,因为存在“测试版”。它在运行 t1 之前启动并完成。

t1 has been launched. (Main Thread=1)
Task=2, obj=alpha, Thread=3

这是 t1(ID 为 2)。

Task=3, obj=gamma, Thread=1

这是 t3。

【讨论】:

  • 我是个傻瓜,没有注意到这一点,谢谢。我误读了结果!非常感谢!
  • @James,由此产生的一个有趣结果是,任务 ID 显然是在调度任务时设置的,而不是在构建任务时设置的。
  • 好地方,如果可以的话,我会给你一个 +2,因为这样可以避免我依赖 ID。
【解决方案2】:

如果没有某种形式的同步,则不能保证(即非确定性)线程或将 Tasks 分配给线程。

【讨论】:

  • 所以一个任务可以在没有调用 .Start() 或由工厂创建的 .StartNew() 的情况下开始?
  • 啊,这是我的问题,为什么任务似乎不服从开始,直到被告知这样做。
  • 这一行你调试了吗?
  • 我重写了这个问题,更准确地说,我做了更多的调试来试图弄清楚这一点,但丹已经证明了我的误解。无论如何谢谢你。
【解决方案3】:

当您启动一个任务时,它可能不会立即执行(如果没有空闲线程池线程)。但任务永远不会自己开始。而且你观察到的输出是正确的。

代码执行如下:

  • t1 (alpha) 已创建,但未执行
  • t2 (beta) 被创建、启动、打印到控制台(显然是 TaskId == 1)并等待
  • t1 (alpha) 已启动,显然是 TaskId == 2
  • 已打印关于启动t1 的通知
  • t1 (alpha) 打印到控制台并等待
  • 其余的应该是显而易见的

【讨论】:

  • +1 以获得好的答案,以及更早的答案。尽管我首先阅读了丹的答案并将其标记为答案,但由于响应的顺序很奇怪。
  • @James,分数相同的答案是随机排序的。而且我认为您可以改变主意,接受的答案是什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-08
相关资源
最近更新 更多