事件驱动编程:回调与消息轮询

Event-driven programming: callback vs message polling

本文关键字:消息 回调 编程 事件驱动      更新时间:2023-10-16

作为一名C++程序员,我一直在研究OpenGL编程,并了解了处理事件驱动编程的两种主要方法:消息轮询或回调函数。

  • 我看到本机Win32API使用了一个回调函数,该函数由DispatchMessage函数触发。

  • SDL(基于教程)也使用某种回调或类似回调的编程。

  • GLFW也使用回调。

  • SFML允许程序员在代码的任何地方轮询单个消息,通常是在一个循环中,形成消息循环。

  • 基于我所看到的,X Window系统也使用消息轮询。

显然,由于事件系统存在于突出的环境中,每个系统都必须具有优势。我希望有人能告诉我每种方法的优点和缺点。我正在考虑编写一些在很大程度上依赖于事件驱动编程的程序,并希望在选择哪条道路上做出最佳决定。

这并不完整,但我想到了一些事情。。。

我只在3D中使用过GL,在GUI方面没有做太多工作。对事件进行投票是很常见的。更准确地说,在主渲染循环中进行轮询,该循环处理队列中的所有事件,然后继续渲染。这是因为在收集所有事件并使用它们更新场景的3D状态后,可以在每帧从头开始重新渲染所有内容。由于屏幕只能以有限的帧速率显示图像,因此在轮询期间睡眠也是很常见的,因为即使事件提前触发,任何状态更新也要晚些时候才会显示。

  • 如果你要完全按照事件发生的方式处理事件,比如绘制的中途,那么你就有了比赛条件。处理这个问题可能是不必要的。

  • 如果你有任何动画,那么你已经有了一个循环,相比之下,轮询是一个微不足道的成本。

  • 如果你的事件非常罕见,那么你不需要经常重新绘制,所以让线程处于活动状态和轮询有点效率。

  • 如果事件堆积起来,而你又在为每一个事件重新绘制,那就太糟糕了。您可能会发现,与使用循环处理所有事件并渲染一次相比,重新绘制的频率更高。

我认为民意调查的主要问题是不活跃的窗口没有得到关注。假设您最小化GL应用程序。你知道它不会接收任何事件,所以轮询是无用的。绘画也是如此。

另一个问题是响应延迟。这对于像在游戏中捕捉鼠标移动这样的东西来说是非常重要的。只要您按正确顺序轮询事件(输入→使现代化→display)这通常是可以的。然而,vsync可能会延迟显示帧,从而扰乱时序。

我目前正在为linux创建基于openglevdev的轻量级GUI库。

第一个是在C中开发的,受pipe用于多线程通信的启发,我实现了消息体系结构。

对于第二个,在c++中,我只使用回调,但linux中的evdev堆栈是消息驱动的。

我的结论是,对于外围设备(例如:鼠标),它可以比程序更快地触发中断,你需要一个fifo层(通常是一个管道),使两个上下文之间的通信异步。因此:消息只是多线程环境中的异步缓冲回调。

您也可以使用回调fifo来缓冲您的事件。但是,在线程之间组织变量并不总是那么容易(信号量、锁定等)。使用消息作为唯一的进程间同步机制有助于澄清这一点。