一个真实的事件循环

仅从一个系统收集数据的简单程序只需要一个(阻塞)事件循环。 例如,Windows应用程序有消息循环,POSIXnetworking程序通常有select / epoll / etc。 在他们的核心循环中,纯SDL游戏使用SDL的事件循环。 但是如果你需要从几个子系统收集事件呢? 如不使用SDL_net进行联网的SDL游戏。

我可以想到几个解决scheme:

  1. 投票(呃)
  2. 把每个事件循环放在它自己的线程中,并且:

    1. 将消息发送到收集和处理事件的主线程,或者
    2. 将每个线程的事件处理代码置于关键部分,以便线程可以asynchronous等待事件,但同步处理它们
  3. 为主事件循环select一个子系统,并通过该子系统将其他子系统的事件作为自定义消息(例如,Windows消息循环和自定义消息,或者一个套接字select()循环以及通过环回连接传递事件)传递。

请注意,我正在讨论一个事件循环,它会阻止执行,直到事件到达。 这允许编写基于事件的游戏,不会毫无意义地刻录100%的CPU,甚至可以在绘制或执行逻辑更新期间处理事件。 检查子系统是否有事件并继续执行,否则就是我所说的轮询。

在消息传递是一个发展良好的线程原语(例如在D编程语言中 )的平台上,选项2.1更加有趣,但2.2看起来对我来说是最好的select。

所以,我现在正在使用的技术有一个由所有线程通过订阅和重复共享的中心消息stream的概念(线程安装处理程序可能或不可能重复消费的消息)。

该stream由专用于翻译/轮询不同事件队列/设备的线程馈送。 如果需要的话,因为事件源都暴露相同的API到这个线程,我可以(例如,XInput似乎只是轮询的情况下)创建一个包含专门处理特定types的input的线程的类; 这使我能够处理360控制器和asynchronous社交媒体查询等多种事物。

有一个好的事情,这个统一的stream也是我可以做怪异的事情,如有一个处理程序,消耗事件和模式匹配他们与国家机器来处理的东西,如格斗游戏的攻击组合,然后发出游戏事件“Haruken!”

请记住,像这样的最终目标是将各种各样的input事件组合成一个技术保证正确处理的单一stream(Quake有一个很好的处理)。

我记得通过ChucK http://chuck.cs.princeton.edu/的代码库,并注意到整个程序只使用一个线程。 ChucK是一个有趣的例子,因为它使用“强时限”模型中的一个线程来伪造并发(这是我最好的解释;))。 但是,对于不同的事件源(MIDI事件,打开声音控制事件或套接字消息)有线程,并将这些事件排队以供主循环处理。

所以…我会select选项2.1。 这与选项3相似。

除非你有一个明确的并行性帮助例子,否则向系统添加线程会造成最坏的情况下的错误和效率低下(由于必要的同步),所以我不会在这种情况下使用它。 请注意,您的选项2.1已经遗漏了同步方面 – 因为PostMessage是同步的,所以您可以在Windows上正常工作,但是您需要在每个API的基础上进行检查。

我不会select通过自定义消息将多个子系统路由到另一个子系统,因为如果您更改该子系统,则可能需要大量重写。 从Win32端口到SDL或其他。

所以,我通常会在子系统使其可能和高效的地方进行轮询。 例如。 查询networking库几乎不是什么问题,因为要么有数据准备好读取,要么没有数据 – 如果库制作的很好,你不会通过检查来减慢程序的运行速度。

如果事件循环写得干净,没有理由说主线程不能有两个事件循环。 例如,Windows有PeekMessage。 首先你处理所有的Windows消息,然后你继续处理所有的消息。 只要你没有阻止接收消息的呼叫,那么没有理由不能在一个循环而不是一个循环中调用两个消息查询function。