如何在不阻塞和等待的情况下通知另一个线程上某些消息的主线程?

时间:2010-01-18 00:55:43

标签: c# signals multithreading

我正在编写一个只在我公司内部使用的c#组件。该组件封装了与特定桌面应用程序需要与之通信的许多服务器的通信。服务器可以向组件发送未经请求的消息,这些消息在一个单独的线程中被“捕获”。

我希望这个组件的大部分在其创建线程的上下文中执行。我不希望单独的消息线程进行任何消息处理。相反,我想通知主线程有一条等待处理的消息。想要在创建线程的上下文中执行的原因是库的用户可能不知道多线程,并且我希望能够在可能的情况下同步所有操作。

是否有一种简单的方式来表示正在运行的线程?主线程将进行各种常量处理,并且消息线程将不断旋转等待消息。值得注意的是,消息线程封装在第三方库中。收到消息后,它会执行回调。我想回调做一些像mainthread.notify(message)。

编辑: 对不起,我不太清楚我想要主线程做什么。我不希望主线程立即处理消息线程发送的消息。我希望它在不久的将来某个时候处理消息(比如WinForms Message Loop的工作方式)。

编辑2:

情景:

Console App created on Thread1  
Thread2 created, which spins listening for Messages
Console App runs as normal
Message arrives on Thread2
Thread2 fires event MessageReady(sender, message)
Thread2 continues spinning
At the earliest convenience, Thread1 processes the message from MessageReady

我已经完成了一些阅读,似乎将代码编组到另一个线程是一种非常困难的方式,我怀疑同步这个过程是值得的。

4 个答案:

答案 0 :(得分:1)

不,那是不可能的。在将代码注入其中之前,线程必须处于空闲状态。例如,由Control.BeginInvoke(Windows窗体)或Dispatcher.BeginInvoke(WPF)完成。这些UI库通常需要在UI线程上执行代码,因此它们明确支持编组对UI线程的调用。

线程处于“空闲”状态非常重要。如果.NET支持某种异步注入方法,你会遇到可怕的重入问题。

答案 1 :(得分:1)

如果您的组件位于Windows窗体上,那么这是实现目标的一条途径:

在您的组件代码中:

public event EventHandler MessageReceived;

private void UnsolicitedMessageReceived(...)
{
  if (MessageReceived != null)
  {
   // this will invoke on UI thread
   Parent.Invoke(MessageReceived, this, EventArgs.Empty);
  }
}

在您的表单中,您可能有:

MyCoolComponent1.MessageReceived += new EventHandler(MessageReceived);

private void MessageReceived(object sender, EventArgs e)
{
  // do some stuff here
}

答案 2 :(得分:0)

由于您可能不希望线程只删除它们当前正在执行的操作,因此您需要某种任务队列供线程查看 - 这不一定比任何更高级的队列,其中T是您用来表示每个任务的某种类型。维护一个队列并在那里添加消息,这样线程就可以在完成他们当前正在做的事情时处理它们。

如果队列为空,则使用信号量让工作线程等待新数据,如果向空队列添加新消息,则使用信号量在该信号量上发出脉冲。这可以防止他们在不断轮询队列时浪费CPU周期。

如果你想要几个工作线程,你需要做的就是确保每个线程都有自己的队列,你将完全控制哪个线程运行什么。

编辑:再次阅读问题,我不确定你的问题是否真的需要线程立即做一些工作。如果是这种情况,我无法看到这是可能的,因为你不能只是随机地注入代码 - 你很可能会破坏当时正在执行的任何代码。

答案 3 :(得分:0)

一个选项是将委托从主线程传递给子线程,它们可以用作回调来表示它们有消息。子线程可以通过回调传递消息,该回调将消息保存在基于内存的集合或持久存储中,主线程在适当的时候进行检查。

您可以更进一步,不要让子线程信号通知主线程,而是让子线程将消息写入数据库,并让主线程在方便的时候检查数据库。您甚至可以使用数据库(通过事务)来处理并发。这样可以在系统崩溃时不丢失消息。甚至允许您跨服务器传播子线程(或主线程)。