避免卡住回调

时间:2010-03-08 11:54:38

标签: c++ event-handling callback

这是一个关于通用c ++事件驱动的应用程序设计的问题 让我们假设我们有两个线程,一个是“Dispatcher”(或“Engine”......)和一个“Listener”(或“Client”......)。 我们假设我编写了Dispatcher代码,并将其作为库发布。当然,我也写了Listener界面 Dispatcher执行时(在Listener注册后)

listenerInstance.onSomeEvent();

事件处理代码实际上将由Dispatcher线程执行,因此如果实现Listener的人写了类似

的内容

void Listener::onSomeEvent() { while(true) ; }

调度员将永远陷入困境。

是否有一个“普通的旧c ++”(我的意思是没有boost或libsigc ++)方法来“解耦”这两个类,所以我可以确定我的Dispatcher能够正常工作,无论听众在回调中做什么?

再见,并提前致谢,
安德烈

4 个答案:

答案 0 :(得分:4)

如果事件在同一个线程中被调用(我似乎理解可能是一个要求),那么你可以做的事情并不多。

如果这是在带有消息泵的Win32应用程序下,您可以注册一个Windows消息并使用表示此事件的数据调用PostMessage,您可以修补消息循环以解释该消息并调用该事件。你获得的是各种各样的解耦,事件调用是异步的(即事件调用无论如何都会返回)。但是稍后当你处理你的消息并实际调用事件时,你的主线程仍然会被停顿,除非事件处理程序准备就绪,否则其他任何东西都不会运行。

另一种选择是为您的调用创建一个新线程(或使用线程池)。这不适用于需要某个线程的事件(即ui更新线程)。此外,这会增加同步开销和线程产生开销,您可能会破坏线程和/或CPU时间系统。

但实际上,我不认为图书馆设计师的工作是预测和避免这些问题。如果最终用户想要创建一个长事件处理程序,让他自己生成一个新的线程。如果他没有,只是想让他的特定线程处理一个事件,那就让他吧。它简化了您的工作,不会增加任何不需要的开销。

答案 1 :(得分:3)

我担心没有原生的C ++方法可以做到这一点。对于Windows,您可以使用asynchronous procedure calls (APC)

答案 2 :(得分:2)

一种方法是将onSomeEvent调用为专用线程。这不是100%防弹,但它可以避免while(true);问题。

我希望它有所帮助

答案 3 :(得分:1)

有一种pure C++方法可以实现你所提到的。但是,它非常无效。这是一个示例:

class Listener
{
  bool myHasEvent;

private:
  void ProcessEvent()
  {
    while (true)
    {
      if (!myHasEvent)
        continue;           //spin lock

      // Do real processing
      myHasEvent = false;
    }
  }

public:
  void onSomeEvent() { myHasEvent = true; }
};

但是,我建议不要采用这种方法。相反,我会将其转换为更具特定于平台的代码。我将使用特定于操作系统的等待例程(即Win32上的if (!myHasEvent) continue;)替换WaitForSingleObject自旋锁,并传递事件句柄。然后,在onSomeEvent中,我将事件设置为信号状态(即Win32上的myHasEvent = true;),而不是SetEvent。这样会更有效,因为线程在等待期间不会占用处理器时间。

另一种方法是盲目建议的PostMessage