发生事件时唤醒线程

时间:2010-11-15 19:29:11

标签: c# multithreading events

我想在两个线程之间实现以下通信:

线程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();
        }
    }
}

4 个答案:

答案 0 :(得分:12)

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

如果在等待句柄上调用WaitOne方法,它将阻塞您的线程,直到某个其他线程在同一个等待句柄上调用Set

有两个重要的简单事件等待句柄:AutoResetEvent将在线程通过WaitOne后自动重置。 ManualResetEvent只会在您拨打Reset时自行重置。

答案 1 :(得分:10)

这是一个常见的同步问题,有几种方法(如果你不是非常小心的话,所有这些方法都很容易搞砸):

  1. 等待句柄(Joren已经描述了这些)。

  2. Monitor.WaitMonitor.Pulse。这里有一个问题是Pulse只会唤醒已经处于Wait状态的线程,所以你必须小心如何管理同步对象的锁定。

  3. 使用.NET 4中的新TPL(也可以反向移植到.NET 3.5),您可以设置异步任务并根据以前完成的任务定义任务继续的条件。理解如何构建代码以利用任务和延续有一点学习曲线,但它比通过简单使用低级同步结构的非常艰难的道路要好得多(从长远来看)。 。这也为您提供了一个很好的前进道路,可以为您的逻辑添加更强大的错误处理和取消支持,因为协调这些内容的细节已经融入了TPL。

答案 2 :(得分: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

答案 3 :(得分:2)

通常使用线程来允许&gt; 1项要并行处理的工作。我很好奇为什么你的设计需要线程A睡眠而线程B做某事,然后醒来并继续工作。为什么不让Thread A自己运作呢?

您可能会受益于使用.Net 4的Task Parallel Library - 然后,线程A可以启动异步任务,该任务在单独的线程上自动执行,并且结果可供线程A使用而无需显式的线程间信令(如果线程A或B出现故障,可能会导致应用程序挂起)。