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

时间:2014-11-03 03:54:02

标签: c++ events opengl user-interface callback

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

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

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

  • GLFW也使用回调。

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

  • X Window系统基于我所见,也使用了消息轮询。

显然,由于事件系统存在于突出的环境中,因此每个系统都必须具有优势。我希望有人能告诉我每个人的优点和缺点。我正在考虑编写一些程序,这些程序在很大程度上依赖于事件驱动的编程,并且希望最好地决定采用哪条路径。

2 个答案:

答案 0 :(得分:3)

这不是完整的,但这里有一些想到的事情......

我只使用过GL作为3D,并没有真正做过GUI的方式。轮询事件很常见。更确切地说,在主渲染循环中进行轮询,该循环处理队列中的所有事件,然后继续渲染。这是因为您在收集所有事件并使用它们更新场景的3D状态后,每帧都从头开始重新渲染所有内容。由于屏幕只能以有限的帧速率显示图像,因此在轮询期间睡眠也很常见,因为任何状态更新都不会在以后显示,即使它们的事件更早被触发也是如此。

  • 如果您要完全按照事件处理事件,例如通过绘图中途,那么您就有竞争条件。处理此事可能是一个不必要的麻烦。

  • 如果你有任何动画,那么你已经有了一个循环,相反,轮询是一个微不足道的代价。

  • 如果您的事件非常罕见,那么您不需要经常重新绘制,因此线程处于活动状态并且轮询有点效率低。

  • 如果事件堆积起来并且你正在重新绘制每个事件,那将是非常糟糕的。您可能会发现比使用循环处理所有事件并渲染一次更频繁地重新绘制。

我认为轮询的主要问题是无法关注的非活动窗口。让我们说你最小化你的GL应用程序。你知道它不会收到任何事件,因此轮询是无用的。所以正在为此而努力。

另一个问题是响应延迟。这对于捕捉游戏中的鼠标移动非常重要。只要您按正确的顺序轮询事件(输入→更新→显示),这通常是正常的。但是,vsync可以通过延迟显示帧来搞乱时间。

答案 1 :(得分:0)

我目前正在基于 opengl evdev 为Linux创建轻量级GUI库。

C 中开发的第一个引导我实现消息体系结构,受到管道用于多线程通信的启发。

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

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

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