【发布时间】:2019-06-03 12:31:20
【问题描述】:
我在业余时间写一个视频游戏,在引入多线程时有一个关于数据一致性的问题。
目前我的游戏是单线程的,并且有一个简单的游戏循环,正如许多教程中所教授的那样:
while game window is not closed
{
poll user input
react to user input
update game state
render game objects
flip buffers
}
我现在想在我的游戏中添加一个新功能,让玩家可以自动执行某些冗长乏味的任务,例如长距离步行(快速旅行)。我可能会选择简单地将玩家角色“传送”到他们的目的地,但我不希望这样做。取而代之的是,游戏将加速,玩家角色实际上会像玩家手动行走一样行走。这样做的好处是游戏世界会像往常一样与玩家角色互动,任何可能发生的特殊事件仍然会发生并立即停止快速旅行。
为了实现这个功能,我正在考虑这样的事情:
- 启动一个新线程(工作线程)并让该线程不断更新游戏状态,直到玩家角色到达其目的地
- 让主线程不再像往常一样更新游戏状态和渲染游戏对象,而是以更简单的方式显示旅行进度
- 使用同步消息队列让主线程和工作线程通信
- 当快速旅行完成或取消(由于玩家交互或其他原因)时,工作线程会终止并使用主线程恢复标准游戏循环
在伪代码中可能如下所示:
[main thread]
while game window is not closed
{
poll user input
if user wants to cancel fast travel
{
write to message queue player input "cancel"
}
poll message queue about fast travel status
if fast travel finished or canceled
{
resume regular game loop
} else {
render travel status
flip buffers
}
}
[worker thread]
while (travel ongoing)
{
poll message queue
if user wants to cancel fast travel
{
write to message queue fast travel status "canceled"
return
}
update game state
if fast travel is interrupted by internal game event
{
write to message queue fast travel status "canceled"
return
}
write to message queue fast travel status "ongoing"
}
if travel was finished
{
write to message queue fast travel status "finished"
}
消息队列将是某种双通道同步数据结构。也许有两个 ArrayDeque,每个都有一个 Lock。我相当肯定这不会太麻烦。
我比较关心的是游戏数据的缓存问题:
- 1.a) 会不会是工作线程在启动后可能会看到旧的游戏数据,因为主线程可能运行在缓存了部分结果的不同内核上?
- 1.b) 如果上述情况属实:我是否需要将游戏数据中的每个字段都声明为 volatile,以绝对保证不会出现不一致的数据?
- 2) 如果所有字段都是易变的,我是否可以假设性能会受到不小的影响?
- 3) 由于我只需要在几个线程之间传递数据并且控制良好的时间点,是否可以强制所有缓存写回主内存而不是使用易失性字段?
- 4) 有更好的方法吗?我的概念可能是错误的吗?
感谢您的帮助,并对大量文字感到抱歉。我认为如果您知道预期用途会更容易回答这个问题。
【问题讨论】:
-
它有点宽泛,但您可以使用现有的游戏循环获得相同的结果,只需跳过用户输入阶段并从某种“队列”中获取输入。问题是知道何时根据用户当前位置注入某些输入事件,但我敢肯定,如果您有一个预定义的路径供用户遵循,您可以跟踪他们的位置以及下一个事件将发生什么需要为了继续沿着这条道路 - 就像一个想法
-
是的,但是在快速旅行期间窗口会变得无响应。我希望快速旅行尽可能快,这与 CPU cam 进行计算的速度一样快。游戏窗口的更新速度仍然会受到图形管道的限制。
-
是否可以 100% 保证所有想玩我的游戏的人在未来多年(也许是十年或两年)内总是拥有 SMP?即使是这样,即使我的担忧是不必要的,我仍然一般对我的问题的答案感兴趣。
-
你应该阅读
java memory model
标签: java multithreading volatile cpu-cache game-loop