代码之家  ›  专栏  ›  技术社区  ›  Josh Smeaton

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

  •  1
  • Josh Smeaton  · 技术社区  · 14 年前

    我正在写一个只在公司内部使用的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
    

    我已经做了一些阅读,看起来将代码封送到另一个线程是一种非常困难的方式,我怀疑同步这个过程是否值得这么做。

    4 回复  |  直到 14 年前
        1
  •  1
  •   Hans Passant    14 年前

    不,那是不可能的。在向线程中注入代码之前,线程必须处于空闲状态。例如,这是由control.begininvoke(Windows窗体)或dispatcher.begininvoke(WPF)完成的。这些UI库通常需要在UI线程上执行代码,因此它们对将调用封送到UI线程具有显式支持。

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

        2
  •  1
  •   TheObjectGuy    14 年前

    如果您的组件将在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
    }
    
        3
  •  0
  •   Michael Madsen    14 年前

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

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

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

    编辑:在再次阅读问题时,我不确定您的问题是否是您真正需要线程来立即进行一些工作。如果是这样的话,我看不出这是可能的,因为你不能只在随机时间注入代码——你很可能会破坏当时正在执行的任何代码。

        4
  •  0
  •   Ed Power    14 年前

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

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