如何等待线程完成与.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的这个页面,事件可能会在if
和EventName(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(); }