Rad*_*094 6 c++ multithreading
我有一个经典的物理线程与图形线程问题:
假设我正在运行一个用于物理更新的线程和一个用于渲染的线程.
在物理线程(伪代码)中:
while(true)
{
foreach object in simulation
SomeComplicatedPhysicsIntegration( &object->modelviewmatrix);
//modelviewmatrix is a vector of 16 floats (ie. a 4x4 matrix)
}
Run Code Online (Sandbox Code Playgroud)
并在图形线程中:
while(true)
{
foreach object in simulation
RenderObject(object->modelviewmatrix);
}
Run Code Online (Sandbox Code Playgroud)
现在理论上这不需要锁,因为一个线程只写入矩阵而另一个只是读取,而我并不关心陈旧数据.
更新矩阵的问题不是原子操作,有时图形线程只会读取部分更新的矩阵(即并非所有16个浮点数都被复制,只有部分浮点数),这意味着矩阵的一部分来自一个物理帧, part来自前一帧,这反过来意味着矩阵不再是仿射(即它基本上已被破坏).
有没有好的方法可以在不使用锁的情况下防止这种情况 我读到了使用双缓冲的可能实现,但我无法想象一种在不同步线程的情况下工作的方法.
编辑:我想我真正想要使用的是某种三重缓冲,就像他们在图形显示器上使用的那样......有人知道三重缓冲算法的良好表现吗?
编辑2:确实使用非同步三重缓冲不是一个好的想法(如下面的答案所示).物理线程可以运行多个循环,占用大量CPU并停止图形线程,计算最终从未渲染过的帧.
我选择了一个带有单个锁的简单双缓冲算法,其中物理线程在交换缓冲区之前仅在图形线程之前计算多达1帧.像这样的东西:
物理:
while(true)
{
foreach physicstimestep
foreach object in simulation
SomeComplicatedPhysicsIntegration( &object->modelviewmatrix.WriteBuffer);
LockSemaphore()
SwapBuffers()
UnlockSemaphore()
}
Run Code Online (Sandbox Code Playgroud)
显卡:
while(true)
{
LockSemaphore()
foreach object in simulation
RenderObject(object->modelviewmatrix.ReadBuffer);
UnlockSemaphore()
}
Run Code Online (Sandbox Code Playgroud)
听上去怎么样?
您可以在两个线程之间维护一个共享队列,并实现物理线程,这样它只有在完全填充该矩阵中的所有值后才向队列添加一个矩阵.这假定物理线程在每次迭代时分配一个新矩阵(或者更具体地说,一旦将矩阵放入队列中,矩阵就被视为只读).
因此,只要您的图形线程将矩阵拉出队列,就可以保证完全填充矩阵并生成矩阵时模拟状态的有效表示.
请注意,图形线程需要能够处理队列为一次或多次迭代而为空的情况,并且为每个队列条目进行世界时间戳可能是一个好主意,这样您就有了保持两个线程合理地同步而不使用任何正式的同步技术(例如,不允许图形线程使用任何具有未来时间戳的矩阵,并允许它在队列中跳过,如果下一个矩阵是从过去的太远了).另请注意,您使用的任何队列都必须实现,以便在物理线程尝试在图形线程删除某些内容的同时添加某些内容时不会爆炸.
但我无法想象一种无需同步线程即可工作的方法。
无论您使用哪种方案,同步线程在这里都是绝对必要的。如果没有同步,您将面临物理线程远远领先于图形线程的风险,反之亦然。您的程序(通常是推进时间的主线程)需要控制线程操作,而不是线程机制。
双缓冲是一种让物理线程和图形线程并行运行的方案(例如,您拥有多 CPU 或多核计算机)。物理线程在一个缓冲区上运行,而图形线程在另一缓冲区上运行。请注意,这会导致图形出现滞后,这可能是也可能不是问题。
| 归档时间: |
|
| 查看次数: |
1906 次 |
| 最近记录: |