2010-03-08 62 views
2

这是一个关于通用C++事件驱动的应用程序设计的问题。假设我们有两个线程,一个是“Dispatcher”(或“Engine”...)和一个“Listener”(或“Client”...)。
我们假设我编写了Dispatcher代码,并将其作为库释放。当然,我也编写了Listener接口。
当调度执行(监听器注册后)避免卡住调用回调

listenerInstance.onSomeEvent();

事件处理代码会实际上是由发送器线程执行,因此,如果实现监听的人喜欢

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

写的东西

调度程序将永久停留。

是否有一个“简单的老C++”(我的意思是没有提升或libsigC++)的方式来“解耦”这两个类,所以我可以确定我的Dispatcher可以正常工作,无论Listener在回调中做什么?

再见和感谢提前,
安德烈

+0

您的意见后,我评估了两个解决方案:1)生成一个线程,其目的只是调用回调和2)使用boost或libsigC++。我最后的决定(因为目标平台是一个嵌入式系统)是为了保持一切简单,所以我不会实现这些解决方案:我只是把一个大写的“免责声明”,比如“这个回调的实现必须简单速度快,否则库不能工作,我们建议设置一个应该在客户端主循环中管理的标志“。 – andlomba 2010-03-12 10:23:48

回答

4

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

如果这是在具有消息泵的Win32应用程序下,可以注册一个Windows消息并用代表该事件的数据调用PostMessage,并且可以修补消息循环以解释该消息并调用事件。你所获得的是各种类型的解耦,事件调用是异步的(即事件调用无论如何都会返回)。但是稍后在处理消息并实际调用事件时,主线程仍会停滞,并且只有事件处理程序准备就绪后,才会运行其他任何东西。

另一种方法是为您的呼叫创建一个新线程(或使用线程池)。这对于需要特定线程的事件(例如,更新线程)不起作用。此外,这增加了同步开销和线程产生开销,并且可能使线程和/或CPU时间系统挨饿。

但实际上,我不认为这是图书馆设计者预测和避免这些问题的工作。如果最终用户想要创建一个长事件处理程序,让他自己创建一个新线程。如果他不想,只想要他的具体线索来处理一个事件,让他。它简化了您的工作,并且不会增加任何不需要的开销。

+0

嗨,我同意这样的事实,它可能不是你的工作,以防止不好的使用你的图书馆。 – Seb 2010-03-08 12:15:36

2

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

我希望它能帮助

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上的WaitForSingleObject)替换if (!myHasEvent) continue;自旋锁,并通过事件句柄。然后,在onSomeEvent,而不是myHasEvent = true;我会将事件设置为信号状态(即Win32上的SetEvent)。这将会更加有效,因为线程在等待期间不会占用处理器时间。

另一种方法是PostMessage,如暗示所示。