使用/不使用委托()启动线程

有什么区别:

new Thread(new ThreadStart(SomeFunc)) 

和:

 new Thread( delegate() { SomeFunc();} ) 

此代码在我的计算机上提供奇怪的输出:

 public class A { int Num; public A(int num) { Num = num; } public void DoObj(object obj) { Console.Write(Num); } public void Do() { Console.Write(Num); } } /////// in void main() for (int i = 0; i < 10; i++) { (new Thread(new ThreadStart((new A(i)).Do))).Start(); // Line 1 (new Thread(new ThreadStart(delegate() { (new A(i)).Do(); }))).Start(); // Line 2 (new Thread(delegate() { (new A(i)).Do(); })).Start(); // Line 3 } 

如果仅执行第1行,则输出类似于:

0 2 3 1 5 6 4 7 8 9

这是好的,但如果执行第2行或第3行,输出为:

3 3 3 5 5 7 7 9 9 10

有一些多个数字和一个10很奇怪,循环永远不会以数字10运行。这些背后的诀窍是什么?

谢谢。

代表,你正在捕捉i

区别在于使用new ThreadStart((new A(i)).Do)) ,你在for循环中创建一个新的A实例,其中i作为参数。 这意味着在那时, i的值被采用并发送给构造函数。 因此,您发送的委托不是A的创建,但您实际上是将A实例的Do方法的委托发送给构造函数。

但是,使用delegate() { (new A(i)).Do(); }) delegate() { (new A(i)).Do(); }) (两者都有),你正在向线程发送i的引用。

然后线程需要一些时间来启动,同时for循环继续。 当i在委托中使用i (即线程已经启动), for循环已经移动到3 ,这就是你所看到的。 第二和第三个线程也是如此。 启动三个线程但等待启动线程完成一些工作。 然后创建的线程启动(线程1,2和3)并且他们完成他们的工作。 Windows使用for循环返回到线程,然后继续启动线程4和5。

一些阅读材料:

为了回答你的第一点, delegate() { SomeFunc();}创建一个调用SomeFunc()的函数,而不使用delegate()只是直接使用SomeFunc函数作为ThreadStart方法。

在第二个问题中,您将遇到C#匿名函数的实现细节。 对i所有三个引用都指向相同的 i ,其增加三次。 你在三个函数之间有一个竞争条件,这意味着i可以在启动的线程运行之前多次递增。

‘对象A的构造函数何时被调用?’ 帮助回答这个问题。

new ThreadStart((new A(i)).Do))

执行此行代码时 – 调用构造函数,并由ThreadStart委托保留对新创建的对象A的.Do函数的引用。

在第2行和第3行中,您使用的是匿名委托(在C#2.0中引入)。

 delegate() { (new A(i)).Do(); }) 

在调用委托之前,不会执行匿名委托的内容; 在这种情况下由线程分配时间片来执行此操作。

变量i仅在for循环的开始处声明一次,并且委托内容具有对它的引用(委托将执行此操作) – 当代码执行时,它必须在执行时获取i的值。

这解释了值10.当循环执行完毕后,i的值为10。 如果其中一个线程在循环完成后执行,它将输出10。

为避免出现多个数字问题,您可以创建循环变量的本地副本。 代表将继续参考其自己的icopy版本;

 for (int i = 0; i < 10; i++) { int icopy = i; (new Thread(new ThreadStart(delegate() { (new A(icopy)).Do(); }))).Start(); }