我想在两个线程之间实现以下通信:
线程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();
}
}
}
答案 0 :(得分:12)
这是您通常使用wait handles的地方,特别是事件等待句柄。
如果在等待句柄上调用WaitOne
方法,它将阻塞您的线程,直到某个其他线程在同一个等待句柄上调用Set
。
有两个重要的简单事件等待句柄:AutoResetEvent将在线程通过WaitOne
后自动重置。 ManualResetEvent只会在您拨打Reset
时自行重置。
答案 1 :(得分:10)
这是一个常见的同步问题,有几种方法(如果你不是非常小心的话,所有这些方法都很容易搞砸):
等待句柄(Joren已经描述了这些)。
Monitor.Wait和Monitor.Pulse。这里有一个问题是Pulse只会唤醒已经处于Wait状态的线程,所以你必须小心如何管理同步对象的锁定。
使用.NET 4中的新TPL(也可以反向移植到.NET 3.5),您可以设置异步任务并根据以前完成的任务定义任务继续的条件。理解如何构建代码以利用任务和延续有一点学习曲线,但它比通过简单使用低级同步结构的非常艰难的道路要好得多(从长远来看)。 。这也为您提供了一个很好的前进道路,可以为您的逻辑添加更强大的错误处理和取消支持,因为协调这些内容的细节已经融入了TPL。
答案 2 :(得分:7)
您的代码具有生产者 - 消费者模式的“感觉”,但以错误的方式实施。您绝对不希望以这种方式(或任何实际方式)使用Thread.Suspend
和Thread.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);
}
}
}
在上面的代码Consumer
和Producer
分别相当于您的alphaThread
和betaThread
。
答案 3 :(得分:2)
通常使用线程来允许&gt; 1项要并行处理的工作。我很好奇为什么你的设计需要线程A睡眠而线程B做某事,然后醒来并继续工作。为什么不让Thread A自己运作呢?
您可能会受益于使用.Net 4的Task Parallel Library - 然后,线程A可以启动异步任务,该任务在单独的线程上自动执行,并且结果可供线程A使用而无需显式的线程间信令(如果线程A或B出现故障,可能会导致应用程序挂起)。