5

我有这个简单的代码:(我在 linqpad 中运行

void Main()
{
    for ( int  i=0;i<10;i++)
     {
      int  tmp=i;
      new Thread (() =>doWork(tmp)).Start();
     }
}

 public void doWork( int h)
 {
 h.Dump();
 }

int tmp=i;行用于捕获变量-因此每次迭代都有自己的值。

2个问题:

1)数字不是连续的,而线程执行是!

2)有时我得到的数字少于10 个!

以下是一些执行输出:

在此处输入图像描述在此处输入图像描述在此处输入图像描述在此处输入图像描述

问题

1)为什么会发生案例1,我该如何解决?

2)为什么会发生案例2,我该如何解决?

4

6 回答 6

8

不应期望它们是连续的。每个线程都获得内核选择的优先级。可能会发生它们看起来是连续的,纯粹是每个开始时的性质,但这纯粹是机会。

为了确保它们都完成 - 将每个新线程标记为IsBackground = false,以便它保持可执行文件处于活动状态。例如:

new Thread(() => doWork(tmp)) { IsBackground = false }.Start();
于 2012-05-31T11:33:57.827 回答
2

您不应该期望线程之间有任何排序。

如果您启动一个新线程,它只会被添加到操作系统的管理结构中。最终,线程调度程序将出现并为线程分配一个时间片。它可以以循环方式执行此操作,选择一个随机的,使用一些启发式方法来确定哪个看起来最重要(例如,拥有一个在前台的窗口)等等。

如果输出的顺序是相关的,您可以在之后对其进行排序,或者 - 如果您在工作开始之前就知道顺序 - 使用一个数组,其中每个线程都有一个索引,它应该将其结果写入其中。

以您的示例的方式创建新线程也非常慢。对于微任务,使用线程池至少要快一个数量级。

于 2012-05-31T11:38:06.410 回答
2

线程以不可预知的顺序执行,如果主线程在其他线程之前完成,您将无法获得所有数字(dump() 将不会执行)。如果您将线程标记为 IsBackground = false,您将获得所有线程。第一个没有真正的解决方案,除了不使用线程(或加入线程,这实际上是一样的)。

于 2012-05-31T11:35:51.360 回答
1

线程管理的本质是随机的。您可以解决这两个任务,但开销太大。

  1. 问题出现在控制台(或您用于转储的线程)上并发多个线程,同步机制的覆盖是可能的但很复杂并且会导致性能降低
  2. 在调用所有线程之前退出(请参阅@Marc Gravell 的回答)
于 2012-05-31T11:38:04.953 回答
0

如果排序很重要,您可能希望利用共享队列并使用信号量来确保一次只有一个线程在队列顶部运行

于 2012-05-31T12:12:54.463 回答
0

您可以订购线程执行,但必须由您专门针对特定问题和特定解决方案执行。

例如:您希望线程 1、2、3 完成代码的第 1 阶段,然后它们按照 ID 的顺序(您分配的这些 ID)进入下一阶段。

你可以使用信号量来实现行为——搜索块同步和互斥以及Test-and-set方法。

于 2015-03-02T03:02:19.787 回答