多线程在游戏中共享资源,需要一些想法的反馈
MultiThread in Games sharing resources, Need some feedback on a idea
我最近开始了一个制作游戏的项目(我有点新),我开始思考如何实现多线程来提高性能。
假设你在一个游戏中有一个单位,它有一个位置x
和y
。这个位置是由一个线程从互联网上更新的,另一个线程使用x,y
来渲染单元的图形(它必须知道它在哪里)。
现在假设您在这些变量上放置了一个互斥对象或sephamore(有点不确定哪一个是最好的)。当然,问题出在渲染线程上。你不能停下来等待,比赛会变得滞后。不过,这对互联网线程来说不是问题。除非出了什么问题,否则再过几毫秒对更新游戏无关紧要。
所以我在想如何解决这个问题,我有了一个主意。假设您创建了两组x,y
(从现在起,我们只使用x
来简化它,但您已经明白了)。所以你有x1
和x2
。
- 现在互联网线程只更新了x1
- 图形线程使用x1,然后将x2更新为其当前值
现在这个主意来了。如果x1
处于来自互联网线程的锁定中,图形线程将只显示
"嘿,我等不及了。我会继续使用
x2
,因为这是一个很好的位置近似值。"
并且它将这样做,直到x1
再次空闲。它会看起来像这样。
//Thread Graphics:
if (x1 is not locked){
lock x1:
use x1
unlock x1:
x2=x1
}else{
use x2
}
//Thread Internet:
wait until x1 is unlocked:
lock x1:
save data to x1
unlock x1:
现在我意识到这会占用一些额外的内存,但我认为这是值得的,至少如果你把这项技术的使用限制在关键的数据片段。
所以我的问题是:你们觉得这个主意怎么样?也许这已经是一种常见的技术了,只是我不知道它的名字。如果你对如何解决这样的问题有任何其他反馈,我将不胜感激。我认为这是大多数程序员的常见问题。
我喜欢这个想法,但我担心预测游戏中动作的后果。在我看来,你最好集中精力确保你的互斥对象保护(共享)数据在尽可能小的部分中得到保护。例如,不要在绘制过程中锁定整个对象,而是先锁定,复制所需内容,然后解锁,然后绘制。互联网方面也是如此。。。等待更新,获取更新,锁定,更新,解锁。
在我的游戏中,我在每一帧的末尾运行一个函数列表。
线程1:调用服务器以获取位置
线程2:在X,Y 上渲染对象的帧
线程2:检查来自线程1的工作。
线程2:没有工作,继续。
线程1:接收X,Y!
线程1:创建将设置最终X,Y 的工作对象
线程1:锁定线程2的工作队列。
线程1:将工作对象推送到工作队列
线程1:解锁线程2工作队列。
线程2:在X,Y 上渲染对象的帧
线程2:检查来自线程1的工作。
线程2:找到工作!正在锁定工作队列。。。
线程2:使用线程1工作设置对象X、Y。
线程2:删除工作对象
线程2:解锁工作队列
线程2:继续渲染循环
或者,也可以等待帧渲染完成,暂停片刻,更新值,然后取消暂停渲染线程。
使用额外内存不是个坏主意。
如果在处理数据时不锁定x1,则可以改进算法。
而不是这个
//Thread Graphics:
if (x1 is not locked){
lock x1:
use x1
unlock x1:
x2=x1
}else{
use x2
}
使用类似的东西
//Thread Graphics:
if (x1 is not locked)
lock x1:
x2=x1
unlock x1:
use x2
实际上,复制数据几乎正是我在某个时候(在遥远的未来)想要尝试的。这个想法在C++中也很简单。
如果实现值的基本类型(DualInt、DualFloat等)并提供所有标准运算符,则可以在内部将数据存储在两元素数组中。getter获取元素0,setter修改元素1。
诀窍在于转换它们。您所需要做的就是拥有一个读写器锁,其中getter和setter使用读写器部分,switcher使用写器部分。您可以让多个读者阅读(实际上是变老并设置新值),直到您想要切换。然后,您获取锁的写入器部分(它阻止新的读卡器并等待所有读卡器完成),并切换一个全局变量,该变量指示从哪个元素读取,向哪个元素写入。
不用大惊小怪,不用麻烦,也不用到处复制很多价值观。
这是一种维护线程安全的好方法,如果考虑双缓冲,可以进行扩展。在我参与的项目中,我们有一个线程安全的数据库,它遵循类似的原则:
- 数据有两个副本,写缓冲区和读缓冲区
- 每当数据库被写入时,它都会使用写缓冲区
- 当从中读取时,它使用读取缓冲区
- 在每帧结束时,缓冲区被交换,因此读缓冲区现在是写缓冲区,反之亦然
您应该能够在渲染线程中看到与双重缓冲的相似之处。这使我们能够在整个项目中保持线程安全。当然,代价是数据库中任何内容的内存使用量都会翻倍,因此它不适合存储大量数据。我们最大的成功通常是渲染数据和AI数据,它们只在单个线程中使用,所以这对我们来说不是什么大问题
编辑:我忘了提到第二个权衡:当我们更改数据库中的值时,它要到下一帧才会生效。这对我们来说并不是一个大问题,我们只需要确保在编写系统时牢记这一点。
- 拥有或在对象之间共享资源
- 在新作用域中使用unique_lock是否等效于在使用共享资源的工作结束时解锁调用
- 是否有一种设计模式或面向对象的基本原则来处理这种共享资源的情况?
- 多线程和共享资源:使用C++定期将数据从缓冲区(数据结构)复制到文件
- 为什么我的程序寻找共享资源.dll而不是Commons.lib
- 多个线程访问共享资源
- C++11 中 3 个线程和 2 个共享资源的同步问题
- 锁定构造函数和析构函数中的共享资源
- qtmake-两个项目/目标之间的共享资源
- 在多线程程序中共享资源 C++ 与 Java
- C++/提升共享资源类,用于管理资源生命周期,如shared_ptr
- 高效读取共享资源
- 从DirectX11到Directx9共享资源
- 使用 std::weak_ptr 共享资源所有权
- 如何将共享资源对象的生存期绑定到其用户生存期的联合中?
- 线程共享资源C++
- CppUtest在测试之间共享资源,未定义引用
- 共享资源,如带宽同步
- 写入互斥的共享资源
- 多线程在游戏中共享资源,需要一些想法的反馈