【问题标题】:How can I notify the main thread of some message on another thread without blocking and waiting?如何在不阻塞和等待的情况下通知主线程另一个线程上的某些消息?
【发布时间】:2010-01-18 13:24:35
【问题描述】:

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

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

是否有一种简单的方法可以向正在运行的线程发出信号?主线程会不停的做各种处理,消息线程会不停的旋转等待消息。可能值得注意的是,消息线程被封装在第三方库中。一旦收到消息,它就会执行回调。我希望回调执行类似 mainthread.notify(message) 的操作。

编辑: 抱歉,我不太清楚我想要主线程做什么。我不希望主线程立即处理消息线程发送的消息。我希望它在不久的将来某个时间处理该消息(例如 WinForms 消息循环的工作方式)。

编辑 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

我已经阅读了一些资料,看来将代码编组到另一个线程是一种相当困难的方式,我怀疑同步这个过程是否值得。

【问题讨论】:

  • 我感觉你没有使用 WCF。我建议你这样做。
  • 不,我没有使用 WCF。发送/检索到服务器的消息是经过许可的,并且提供了库来使用它们。我不认为 WCF 可以在这里帮助我。

标签: c# signals multithreading


【解决方案1】:

不,这是不可能的。线程必须先空闲,然后才能将代码注入其中。例如,这是由 Control.BeginInvoke (Windows 窗体) 或 Dispatcher.BeginInvoke (WPF) 完成的。这些 UI 库通常需要在 UI 线程上执行代码,因此它们明确支持对 UI 线程的封送调用。

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

【讨论】:

  • 您提到的 Control.BeginInvoke 示例正是我在类库中所追求的。组件的主线程并不总是在执行,理论上可能是 WinForms 应用程序的 GUI 线程。像 Windows 消息泵这样的东西是理想的。
  • 在这个线程中检查我的答案:social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/…
  • 我已将此答案标记为正确,但我不会创建 GUI 控件只是为了允许跨线程编组。
【解决方案2】:

如果您的组件将在 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
}

【讨论】:

  • 这是假设该库将在 WinForm 上使用。虽然这是最有可能的情况,但不能保证。
【解决方案3】:

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

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

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

编辑:再次阅读问题时,我不确定您的问题是否是您确实需要线程立即执行某些工作。如果是这种情况,我认为这是不可能的,因为您不能只是随机注入代码 - 您很可能会破坏当时正在执行的任何内容。

【讨论】:

  • 正确,我希望主线程在不久的将来某个时候处理该消息。
  • 这可能有助于准确了解线程在您想要“注入”消息时应该做什么。也许您可以通过使用优先级队列使其工作,因此如果那里发生大量工作,您的传入消息会在任何等待的“空闲”任务之前处理?
【解决方案4】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    • 2014-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-01
    • 1970-01-01
    相关资源
    最近更新 更多