避免死机呼叫回调 这是一个关于C++事件驱动应用程序设计的问题。 让我们假设我们有两个线程,一个“调度程序”(或“引擎”)和一个“侦听器”(或“客户端”。 假设我编写了Dispatcher代码,并将其作为库发布。当然,我还编写了侦听器接口。 调度器执行时(侦听器注册后)
避免死机呼叫回调 这是一个关于C++事件驱动应用程序设计的问题。 让我们假设我们有两个线程,一个“调度程序”(或“引擎”)和一个“侦听器”(或“客户端”。 假设我编写了Dispatcher代码,并将其作为库发布。当然,我还编写了侦听器接口。 调度器执行时(侦听器注册后),c++,event-handling,callback,C++,Event Handling,Callback,listenerInstance.onSomeEvent(); 事件处理代码实际上将由Dispatcher线程执行,因此,如果实现侦听器的人编写类似 void Listener::onSomeEvent(){while(true);} 调度员将永远被卡住 是否有一种“普通的旧c++”(我指的是没有boost或libsigc++)方法来“解耦”这两个类,这样我就可以确保我的调度程序无论侦听器在回调中做什么都能正常工作 再见,提前感谢, Andrea一种方法是将onSomeEvent调用到专用
listenerInstance.onSomeEvent();
事件处理代码实际上将由Dispatcher线程执行,因此,如果实现侦听器的人编写类似
void Listener::onSomeEvent(){while(true);}
调度员将永远被卡住
是否有一种“普通的旧c++”(我指的是没有boost或libsigc++)方法来“解耦”这两个类,这样我就可以确保我的调度程序无论侦听器在回调中做什么都能正常工作
再见,提前感谢,Andrea一种方法是将onSomeEvent调用到专用线程中。这不是100%防弹,但可以避免
while(true)代码>问题
我希望它有助于 < p>恐怕没有本机C++的方式来做这个。对于windows,如果事件在同一个线程中被调用(我似乎理解这可能是一个要求),那么您就可以很好地使用它了
如果这是在带有消息泵的Win32应用程序下,您可以注册windows消息并使用表示此事件的数据调用PostMessage
,您可以修补消息循环以解释该消息并调用事件。您获得的是某种解耦,事件调用是异步的(即无论发生什么,事件调用都将返回)。但稍后,当您处理消息并实际调用事件时,主线程仍将暂停,并且在事件处理程序准备就绪之前不会运行任何其他内容
另一种选择是为您的调用创建一个新线程(或使用线程池)。这不适用于需要特定线程(即ui更新线程)的事件。此外,这会增加同步开销和线程生成开销,并且可能会耗尽系统的线程和/或cpu时间
但实际上,我认为作为图书馆设计师,你的工作不是预测和避免这些问题。如果最终用户想要创建一个长事件处理程序,让他自己生成一个新线程。如果他不这样做,只是想让他特定的线程来处理一个事件,就让他来吧。它简化了您的工作,并且不增加任何不需要的开销。有一种纯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; }
};
然而,我反对这种做法。相反,我会将其转换为更特定于平台的代码。如果(!myHasEvent)继续,我将替换使用操作系统特定的等待例程(即Win32上的WaitForSingleObject
)传递事件句柄的代码>自旋锁。然后,在onSomeEvent
中,而不是myHasEvent=true代码>我会将事件设置为信号状态(即Win32上的SetEvent
)。这将更加有效,因为线程在等待期间不会占用处理器时间
另一种方法是PostMessage
,正如Blindly所建议的那样。您好,我同意这样一个事实,即防止对库的不当使用可能不是您的工作。在您的评论之后,我评估了两种解决方案:1)生成一个线程,其唯一目的是调用回调;2)使用boost或libsigc++。我的最终决定(因为目标平台是一个嵌入式系统)是保持一切简单,所以我不会实现这些解决方案:我只会放一个大写的“免责声明”,类似于“此回调的实现必须简单快速,否则库无法工作。我们建议设置一个应在客户端主循环中管理的标志”。