2012-01-06 96 views
11

我在想什麼是在兩個線程之間實現通信的最佳方式。我有一個線程生成隨機數(類發件人),現在我想有另一個線程(類Receiver),它將接收生成的隨機數。 這是發信人:線程,兩個線程之間的通信c#

public class Sender 
{ 
    public int GenerateNumber(){ 


     //some code 
     return randomNumber; 
    } 
} 

Afcourse的主要功能,我會啓動這些線程:

static void Main(string[] args){ 

    Sender _sender=new Sender(); 
    Thread thread1=new Thread(new ThreadStart(_sender.GenerateNumber)); 

} 

我感謝你的幫助

+0

兩個線程是否同時啓動? Receiver在等待發件人時正在做什麼?發件人在生成隨機數後會做些什麼? – cadrell0 2012-01-06 20:06:34

+0

這是.NET 4嗎? – Yahia 2012-01-06 20:12:23

+0

在主函數中,我將啓動這兩個線程,線程發送程序將工作,然後休眠3秒鐘。另外,我將開始接收數據的線程接收器的實例...basiclly線程將工作untui用戶按esc鍵...接收器將寫入收到的控制檯號碼。 – Avicena00 2012-01-06 20:12:43

回答

2

您將需要某種資源(列表,隊列,等等)在發送者和接收者之間共享。你將不得不同步訪問這個資源,否則你將無法在線程之間傳遞數據。

19

如果您使用.NET 4,我會建議使用更高級別的抽象:Task<TResult>。您的第一個線程可以安排任務(可能最終創建線程,或者安排在現有的任務處理線程上),然後可以檢查狀態,阻止結果等。

如果你想要做的不是一次性的任務越多,你可能需要使用一個生產者/消費者隊列 - 再次,.NET 4的幫助與通過BlockingCollection<T>

+1

I知道我必須深入閱讀C#,所以今晚將開始:) – Avicena00 2012-01-06 21:15:42

+1

@AintMeBabe:說實話,C#深入幾乎沒有觸及新的任務東西......通過MSDN研究任務並行庫博客文章可能比這本書更直接受益。當然不是我會長期勸阻你:) – 2012-01-06 21:30:59

+0

如果我們不能控制生產者,那該怎麼辦?在我的上下文中,線程A(在我的控制下)做了一些事情,它需要等待線程B提出事件;線程B由一個庫產生。我聽這個事件。事件監聽器(在線程B中運行)應該如何通知線程A?我想不出除了一個ManualResetEvent。 .net 4中有更好的方法嗎? – Jimmy 2016-08-23 17:26:31

0

如果你正在做的是在一個線程中生成一個隨機數,我可能會創建一個線程安全對象來代替它。

lock(syncRoot) 
{ 
    myCurrentRandom = Generate(); 
    return myCurrentRandom; 
} 
+0

好點,這只是一個功能,我測試得到的東西工作後,線程發送器會有更多的方法 – Avicena00 2012-01-06 20:16:31

6

下面是一個使用WaitHandle的一種可能的方法:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     using (ManualResetEvent waitHandle = new ManualResetEvent(false)) 
     { 
      // have to initialize this variable, otherwise the compiler complains when it is used later 
      int randomNumber = 0; 

      Thread thread1 = new Thread(new ThreadStart(() => 
      { 
       randomNumber = _sender.GenerateNumber(); 

       try 
       { 
        // now that we have the random number, signal the wait handle 
        waitHandle.Set(); 
       } 
       catch (ObjectDisposedException) 
       { 
        // this exception will be thrown if the timeout elapses on the call to waitHandle.WaitOne 
       } 
      })); 

      // begin receiving the random number 
      thread1.Start(); 

      // wait for the random number 
      if (waitHandle.WaitOne(/*optionally pass in a timeout value*/)) 
      { 
       _receiver.TakeRandomNumber(randomNumber); 
      } 
      else 
      { 
       // signal was never received 
       // Note, this code will only execute if a timeout value is specified 
       System.Console.WriteLine("Timeout"); 
      } 
     } 
    } 
} 

public class Sender 
{ 
    public int GenerateNumber() 
    { 
     Thread.Sleep(2000); 

     // http://xkcd.com/221/ 
     int randomNumber = 4; // chosen by fair dice role 

     return randomNumber; 
    } 
} 

public class Receiver 
{ 
    public void TakeRandomNumber(int randomNumber) 
    { 
     // do something 
     System.Console.WriteLine("Received random number: {0}", randomNumber); 
    } 
} 


我只是想更新我的答案提供什麼,我認爲是使用在 Task<TResult>類上面例子中的等價代碼。 NET S 4在Jon Skeet的回答中指出。信用歸功於他指出。謝謝,Jon。我還沒有理由使用該課程,並且當我看到使用這個課程有多容易時,我感到非常驚喜。

除了使用該課程獲得的性能優勢之外,使用Task<TResult>類編寫等效代碼似乎更容易。例如,如下所示的主要方法上面可以改寫爲體:

 Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     Task<int> getRandomNumber = Task.Factory.StartNew<int>(_sender.GenerateNumber); 

     // begin receiving the random number 
     getRandomNumber.Start(); 

     // ... perform other tasks 

     // wait for up to 5 seconds for the getRandomNumber task to complete 
     if (getRandomNumber.Wait(5000)) 
     { 
      _receiver.TakeRandomNumber(getRandomNumber.Result); 
     } 
     else 
     { 
      // the getRandomNumber task did not complete within the specified timeout 
      System.Console.WriteLine("Timeout"); 
     } 

如果你沒有必要指定任務超時,且內容無限期地等待它完成,然後你可以寫這使用更少的代碼:

 Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     Task<int> getRandomNumber = Task.Factory.StartNew<int>(_sender.GenerateNumber); 

     // begin receiving the random number 
     getRandomNumber.Start(); 

     // ... perform other tasks 

     // accessing the Result property implicitly waits for the task to complete 
     _receiver.TakeRandomNumber(getRandomNumber.Result); 
+0

謝謝你謝謝:) – Avicena00 2012-01-06 20:46:02

+0

豎起大拇指!!!!!! – Avicena00 2012-01-06 20:46:21

+0

@AintMeBabe - 如果您使用.NET 4,那麼我不得不建議您查看Jon Skeet的答案。看起來你可以使用'Task '類來做更少的代碼。 – 2012-01-06 20:54:13

0

實現兩個線程之間通信的「最佳」方式實際上取決於需要傳達的內容。你的例子似乎是一個經典的生產者/消費者問題。我會使用同步隊列。查看Synchronized Collections的MSDN文檔。您可以使用Queue.Synchronized方法爲Queue對象獲取同步包裝器。然後,讓生產者線程調用Enqueue()和消費者調用Dequeue()。