2010-11-15 103 views
6

我想實現兩個線程之間的以下通信:當事件發生時喚醒線程

線程Alpha會執行某些操作,然後暫停自己。接下來的第二個線程(Beta)引發並重啓Alpha線程。循環繼續......

我做了類似下面的事情,但我不確定它是否是一個適當的設計。另外我注意到Thread.Suspend()Thread.Resume()已被棄用。我期待着聽到關於這個實現的任何建議,以及替代已棄用方法的優先選擇。

namespace ThreadTester 
{ 
    delegate void ActionHandler(); 

    class Alpha 
    { 
     internal Thread alphaThread; 
     internal void Start() 
     { 
      while (true) 
      { 
       this.alphaThread.Suspend(); 
       Console.WriteLine("Alpha"); 
      } 
     } 
     internal void Resume() 
     { 
      while (this.alphaThread.ThreadState == ThreadState.Suspended) 
      this.alphaThread.Resume(); 
     } 
    } 

    class Beta 
    { 
     internal event ActionHandler OnEvent; 
     internal void Start() 
     { 
      for (int i = 0; i < 15; i++) 
      { 
       OnEvent(); 
       Thread.Sleep(1000); 
      } 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Alpha alpha = new Alpha(); 
      alpha.alphaThread = new Thread(new ThreadStart(alpha.Start)); 
      alpha.alphaThread.Start(); 
      while (!alpha.alphaThread.IsAlive) ; 

      Beta beta = new Beta(); 
      beta.OnEvent += new ActionHandler(alpha.Resume); 
      Thread betaThread = new Thread(new ThreadStart(beta.Start)); 
      betaThread.Start(); 
     } 
    } 
} 

回答

1

通常,線程用於允許並行處理> 1項工作。我很好奇你的設計爲什麼需要線程A在線程B做些什麼時睡覺,然後醒來繼續工作。爲什麼不只是讓線程A自己工作呢?

您可能會從使用.Net 4的Task Parallel Library受益 - 線程A然後可以啓動一個異步任務,該任務在單獨的線程上自動執行,並且結果可用於線程A而不需要顯式的線程間信號傳輸如果線程A或B發生故障,可能會導致掛起的應用程序)。

12

這是您通常使用wait handles的地方,特別是事件等待句柄。

如果您在等待句柄上調用WaitOne方法,它將阻塞您的線程,直到某個其他線程在同一等待句柄上調用Set

事件等待句柄有兩個重要的簡單口味:AutoResetEvent會在線程通過WaitOne後自動重置。 ManualResetEvent只會在撥打Reset時自行重置。

10

這是一個常見的同步問題,有幾種方法(所有這些都是很容易陷入困境,如果你不是非常小心):

  1. 等待句柄(淨蓮已經描述了這些)。

  2. Monitor.WaitMonitor.Pulse。這裏的一個問題是Pulse只會喚醒已處於Wait狀態的線程,因此您必須小心如何管理同步對象的鎖定。

  3. 使用.NET 4中的新TPL(也可以移植到.NET 3.5),您可以設置異步任務並根據以前完成的任務定義任務繼續的條件。瞭解如何構建代碼以利用任務和延續,有一點學習曲線,但它比從事更簡單的低級同步構造之後的非常艱難的道路要好得多(從長遠來看) 。這也爲您向邏輯添加更強大的錯誤處理和取消支持提供了一個很好的途徑,因爲協調這些問題的基本細節已經融入到TPL中。

7

您的代碼具有生產者 - 消費者模式的「感覺」,但以錯誤的方式實現。您絕對不希望以這種方式(或實際上任何方式)使用Thread.SuspendThread.Resume。通過BlockingCollection類實現規範的生產者 - 消費者模式,實際上很容易獲得您想要的排序和信號。

public class ProducerConsumer 
{ 
    private BlockingCollection<object> m_Queue = new BlockingCollection<object>(); 

    public ProducerConsumer() 
    { 
     new Thread(Producer).Start(); 
     new Thread(Consumer).Start(); 
    } 

    private void Consumer() 
    { 
     while (true) 
     { 
      object item = m_Queue.Take(); // blocks when the queue is empty 
      Console.WriteLine("Consumer"); 
     } 
    } 

    private void Producer() 
    { 
     while (true) 
     { 
      m_Queue.Add(new object()); 
      Thread.Sleep(1000); 
     } 
    } 
} 

在上面的代碼ConsumerProducer將分別等於您alphaThreadbetaThread

+0

這可能最接近回答問題的真實意圖,儘管很難確定。新的BlockingCollection絕對是實現這種簡單Producer-Consumer模式的更好方式,而不是直接使用低級別同步構造。也就是說,我建議OP謹慎使用這種模式,因爲我已經看到它無法實現(我已經看到至少有一個應用程序,其中有幾十個線程都運行着它們自己的Producer-Consumer'消息'消息處理程序[有三種完全不同的本地模式實現,不會少]。) – 2010-11-16 01:05:49