[英]How can I wait for a thread to finish with .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();
}
所以,本質上,我怎樣才能讓一個線程等待另一個線程完成? 做這個的最好方式是什么?
我可以看到五個可用選項:
就像米奇的回答一樣。 但這會阻塞你的 UI 線程,但是你會得到一個內置的 Timeout。
WaitHandle
ManualResetEvent
是 jrista 建議的WaitHandle
。
需要注意的一點是,如果您想等待多個線程: WaitHandle.WaitAll()
默認不會工作,因為它需要一個MTA線程。 您可以通過使用MTAThread
標記您的Main()
方法來解決此問題 - 但是這會阻止您的消息泵,並且不推薦從我讀過的內容中。
請參閱Jon Skeet 關於事件和多線程的此頁面。 在if
和EventName(this,EventArgs.Empty)
之間,一個事件可能會被取消訂閱——它以前發生在我身上。
(希望這些編譯,我沒有嘗試過)
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);
}
}
}
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)
我很想知道使用委托和事件進行線程通知之間的區別,我知道的唯一區別是事件是同步調用的。
這個問題的答案非常清楚地描述了您使用這種方法的選擇。
事件/委托的處理方式意味着您的事件處理程序方法位於 thread1/thread2而不是主 UI 線程,因此您需要在 HandleThreadDone 方法的頂部切換回:
// Delegate example
if (InvokeRequired)
{
Invoke(new Action(HandleThreadDone));
return;
}
添加
t1.Join(); // Wait until thread t1 finishes
在你啟動它之后,但這不會完成太多,因為它與在主線程上運行的結果基本相同!
如果您想了解 .NET 中的線程,我強烈建議您閱讀 Joe Albahari 的C# 中的線程免費電子書。
如果從 .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
}
}
From:創建多個線程並等待所有線程完成
前兩個答案很棒,適用於簡單的場景。 但是,還有其他方法可以同步線程。 以下也將起作用:
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 等簡單但非常常見的工具更豐富的線程同步功能。
它們還可以用於同步兩個以上的線程,從而允許復雜的場景,例如協調多個“子”線程的“主”線程、相互依賴的多個階段的多個並發進程進行同步等。
你想要Thread.Join()
方法,或者它的重載之一。
我會讓你的主線程將一個回調方法傳遞給你的第一個線程,當它完成后,它將調用主線程上的回調方法,它可以啟動第二個線程。 這可以防止您的主線程在等待 Join 或 Waithandle 時掛起。 無論如何,將方法作為委托傳遞對於學習 C# 來說是一件有用的事情。
嘗試這個:
List<Thread> myThreads = new List<Thread>();
foreach (Thread curThread in myThreads)
{
curThread.Start();
}
foreach (Thread curThread in myThreads)
{
curThread.Join();
}
我采取了一些不同的方法。 以前的答案中有一個計數器選項,我只是應用它有點不同。 當線程啟動和停止時,我正在關閉許多線程並增加一個計數器並減少一個計數器。 然后在 main 方法中,我想暫停並等待線程完成。
while (threadCounter > 0)
{
Thread.Sleep(500); // Make it pause for half second so that we don’t spin the CPU out of control.
}
這記錄在我的博客文章中:http: //www.adamthings.com/post/2012/07/11/ensure-threads-have-finished-before-method-continues-in-c/
當我希望 UI 能夠在等待任務完成時更新其顯示時,我使用了一個 while 循環來測試線程上的 IsAlive:
Thread t = new Thread(() => someMethod(parameters));
t.Start();
while (t.IsAlive)
{
Thread.Sleep(500);
Application.DoEvents();
}
此實現與@jrista 基於ManualResetEvent
的示例略有不同,因為它顯示了各種選項如何像紅色或綠色交通燈。
public System.Threading.AutoResetEvent thread1done = new System.Threading.AutoResetEvent(false);
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
{
thread1done.Set(); //set traffic light to green before threading
StartTheActions();
}
public void StartTheActions()
{
Thread t1 = new Thread(action1);
t1.Start();
thread1done.WaitOne(); //traffic light is red, until thread1done.Set inside action1()
Thread t2 = new Thread(action2);
t2.Start();
}
public void action1()
{
Thread.Sleep(5000);
//.... do some work
thread1done.Set(); //work is done, set traffic light to green at thread1done.WaitOne()
}
public void action2()
{
MessageBox.Show("Now processing action2");
}
另一種方法是在一個線程中使用 lock(someObject) 和 Monitor.Wait(someObject[,timeout]),在另一個線程中使用 lock(someObject) 和 Monitor.Pulse(someObject)。 SomeObject 在所有 4 次調用中必須是同一個類的實例。 SomeObject 不能是結構。
第一個線程鎖定 someObject,然后調用 Monitor.Wait() 釋放鎖,因此第二個線程可以鎖定 someObject。 當第二個線程完成時,它調用 Monitor.Pulse(),然后第一個線程的 Monitor.Wait() 結束。
示例: someObject 是一個隊列,第一個線程等待第二個線程將對象放入隊列,然后將該對象出隊。
我以前從未真正在C#中使用過線程,在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();
}
因此,從本質上講,我如何讓一個線程等待另一個線程完成? 做這個的最好方式是什么?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.