C++ - 每 X 毫秒执行一次函数

C++ - Execute function every X milliseconds

我似乎找不到一个好的答案:

我正在制作游戏,我希望将逻辑循环与图形循环分开。换句话说,我希望游戏每 X 毫秒进行一次循环,而不管它显示了多少 frames/second。

显然他们都会共享很多变量,所以我不能 thread/timer 来回传递一个变量...我基本上只是在寻找一种方法来拥有一个计时器在后台每X毫秒发出一个标志来执行逻辑循环,而不管图形循环在哪里。

我愿意接受任何建议。看起来最好的选择是有 2 个线程,但我不确定它们之间最好的通信方式是什么,而不需要不断同步大量数据。

您可以将绘制和更新方法附加到所有游戏组件。这样你就可以设置它,当你的游戏是 运行 时调用更新并忽略平局或两者的任意组合。它还具有保持逻辑和图形完全分离的好处。

难道你不能为每个需要绘制的对象设置一个绘制方法并使它们成为全局对象吗?然后 运行 你的渲染线程有一个睡眠延迟。只要您的渲染线程不向全局变量写入任何信息,您就应该没问题。查找 sfml 以查看它的实际示例。

如果您 运行 正在 unix 系统上使用,您可以使用 usleep(),但是 windows 上不可用,因此您可能需要查看 here 的替代方案.

您可以通过让您的 "world view" 在每次滴答中交换来很好地进行多线程处理。所以这是它的工作原理:

  1. 您当前的世界观由单个智能指针指向,并且只读,因此无需锁定。
  2. 您的逻辑创建您的(第一个)世界视图,发布它并安排渲染器。
  3. 您的渲染器获取指向您的世界视图的指针的副本并渲染它(记住,只读)
  4. 与此同时,你的逻辑创造了一个新的、略有不同的世界观。
  5. 完成后,它会交换指向当前世界观的指针,将其发布为当前世界观。
  6. 即使渲染器仍然忙于旧世界视图,也不需要锁定。
  7. 最终渲染器完成渲染(旧)世界。它抓住了新的世界观,开始了另一个运行.
  8. 同时,...(转到第 4 步)

您唯一需要的锁定是在您发布或获取指向世界的指针时。作为替代方案,您可以进行原子交换,但您必须确保使用可以做到这一点的智能指针。

大多数工具包都有一个事件循环(构建在一些多路复用系统调用之上,如 poll(2) -or the obsolete select-...), e.g. GTK has g_application_run (which is above:) gtk_main which is built above Glib main event loop (which in fact does a poll or something similar). Likewise, Qt has QApplication and its exec 方法。

很多时候,您可以在事件循环中注册定时器。对于 GTK,使用 GTimers, g_timeout_add etc. For Qt learn about its timers.

很多时候,你也可以注册一些idle或者background处理,这是你的函数之一,由事件启动在处理完其他事件和超时后循环。您的空闲函数预计会 运行 快速(通常它会在几毫秒内执行一些小的 step 一些计算,以保持 GUI 响应)。对于 GTK,使用 g_idle_add 等。IIRC,在 Qt 中,您可以使用延迟为 0 的计时器。

因此您甚至可以使用超时和空闲处理编写(概念上的)单线程应用程序。

当然,你可以使用多线程:一般主线程是运行宁事件循环,其他线程可以做其他事情。您有同步问题。在 POSIX 系统上,一个不错的同步技巧可能是使用 pipe(7) to self: you set up a pipe before running the event loop, and your computation threads may write a few bytes on it, while the main event loop is "listening" on it (with GTK, using g_source_add_poll or async IO or GUnixInputStream etc.., with Qt, using QSocketNotifier 等....)。然后,在该管道的主循环中的输入处理程序 运行ning 中,您可以使用互斥锁等访问传统的全局数据...

从概念上讲,阅读 continuations。这是一个相关的概念。