2010-11-15 114 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