如何等待线程完成与.NET?

在C#中,我从来没有真正使用线程,我需要有两个线程,以及主UI线程。 基本上,我有以下。

public void StartTheActions() { //Starting thread 1.... Thread t1 = new Thread(new ThreadStart(action1)); t1.Start(); // Now, I want for the main thread (which is calling `StartTheActions` method) // to wait for `t1` to finish. I've created an event in `action1` for this. // The I wish `t2` to start... Thread t2 = new Thread(new ThreadStart(action2)); t2.Start(); } 

所以,基本上,我的问题是如何让一个线程等待另一个完成。 什么是最好的方法来做到这一点?

我可以看到5个选项可用:

1.线程join

和米奇的回答一样。 但是这会阻止你的UI线程,但是你会得到一个为你设置的超时。


2.使用WaitHandle

按照jrista的build议, ManualResetEvent是一个WaitHandle

有一件事要注意的是,如果你想等待多个线程, WaitHandle.WaitAll()默认不起作用,因为它需要一个MTA线程。 你可以通过用MTAThread标记你的Main()方法来解决这个MTAThread – 但是这会阻止你的消息泵,并且不会从我读的东西中推荐。


3.发起一个事件

关于事件和multithreading,请参阅Jon Skeet的这个页面,事件可能会在ifEventName(this,EventArgs.Empty)之间变成unsubcribed事件 – 这在我之前就已经发生了。

(希望这些编译,我没有尝试过)

 public class Form1 : Form { int _count; void ButtonClick(object sender, EventArgs e) { ThreadWorker worker = new ThreadWorker(); worker.ThreadDone += HandleThreadDone; Thread thread1 = new Thread(worker.Run); thread1.Start(); _count = 1; } void HandleThreadDone(object sender, EventArgs e) { // You should get the idea this is just an example if (_count == 1) { ThreadWorker worker = new ThreadWorker(); worker.ThreadDone += HandleThreadDone; Thread thread2 = new Thread(worker.Run); thread2.Start(); _count++; } } class ThreadWorker { public event EventHandler ThreadDone; public void Run() { // Do a task if (ThreadDone != null) ThreadDone(this, EventArgs.Empty); } } } 

4.使用委托

 public class Form1 : Form { int _count; void ButtonClick(object sender, EventArgs e) { ThreadWorker worker = new ThreadWorker(); Thread thread1 = new Thread(worker.Run); thread1.Start(HandleThreadDone); _count = 1; } void HandleThreadDone() { // As before - just a simple example if (_count == 1) { ThreadWorker worker = new ThreadWorker(); Thread thread2 = new Thread(worker.Run); thread2.Start(HandleThreadDone); _count++; } } class ThreadWorker { // Switch to your favourite Action<T> or Func<T> public void Run(object state) { // Do a task Action completeAction = (Action)state; completeAction.Invoke(); } } } 

如果你使用_count方法,可能是一个想法(为了安全起见)使用它

Interlocked.Increment(ref _count)

我有兴趣知道使用代理和事件线程通知之间的区别,我知道的唯一区别是事件被称为同步。


5.代之以asynchronous执行

这个问题的答案有一个非常清楚的描述你的select这种方法。


委托/事件在错误的线程

事件/委托的做事方式意味着你的事件处理方法在thread1 / thread2 而不是主UI线程上 ,所以你需要在HandleThreadDone方法的顶部切换回来:

 // Delegate example if (InvokeRequired) { Invoke(new Action(HandleThreadDone)); return; } 

 t1.Join(); // Wait until thread t1 finishes 

在你启动之后,但是这不会有太大的成就,因为它和主线程运行的结果是一样的!

如果您想了解.NET中的线程,我强烈推荐阅读Joe Albahari的C#免费电子书的线程。

前两个答案很好,并且适用于简单的场景。 然而,还有其他的方法来同步线程。 以下内容也将起作用:

 public void StartTheActions() { ManualResetEvent syncEvent = new ManualResetEvent(false); Thread t1 = new Thread( () => { // Do some work... syncEvent.Set(); } ); t1.Start(); Thread t2 = new Thread( () => { syncEvent.WaitOne(); // Do some work... } ); t2.Start(); } 

ManualResetEvent是.NET框架提供的各种WaitHandle之一。 它们可以提供比简单但非常常见的工具(如lock()/ Monitor,Thread.Join等)更丰富的线程同步function。它们也可用于同步两个以上的线程,从而允许复杂的场景,如“主”线程协调多个“子”线程,多个并发进程,这些进程依赖于彼此的几个阶段进行同步,等等。

如果从.NET 4使用此示例可以帮助您:

 class Program { static void Main(string[] args) { Task task1 = Task.Factory.StartNew(() => doStuff()); Task task2 = Task.Factory.StartNew(() => doStuff()); Task task3 = Task.Factory.StartNew(() => doStuff()); Task.WaitAll(task1, task2, task3); Console.WriteLine("All threads complete"); } static void doStuff() { //do stuff here } } 

来自: https : //stackoverflow.com/a/4190969/1676736

您需要Thread.Join()方法或其重载之一 。

我会让你的主线程传递一个callback方法到你的第一个线程,当它完成时,它会调用mainthread的callback方法,它可以启动第二个线程。 这使您的主线程在等待Join或Waithandle时不会挂起。 作为代表传递方法是一个有用的东西学习与C#无论如何。

发布也许可以帮助其他人,花了相当多的时间寻找像我想出的解决scheme。 所以我采取了一些不同的方法。 上面有一个计数器选项,我只是应用它有点不同。 我旋转了大量的线程,增加了一个计数器,并在线程启动和停止时递减一个计数器。 然后在主要的方法,我想暂停,等待线程完成我做的。

 while (threadCounter > 0) { Thread.Sleep(500); //Make it pause for half second so that we don't spin the cpu out of control. } 

logging在我的博客上。 http://www.adamthings.com/post/2012/07/11/ensure-threads-have-finished-before-method-continues-in-c/

尝试这个:

 List<Thread> myThreads = new List<Thread>(); foreach (Thread curThread in myThreads) { curThread.Start(); } foreach (Thread curThread in myThreads) { curThread.Join(); }