2012-01-06 97 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()。