Mat*_*out 8 c++ multithreading boolean volatile thread-safety
我读过的关于volatile的一切都说它永远不会安全,但我仍然倾向于尝试它,而且我还没有看到这个特定场景被宣布为不安全.
我有一个单独的线程渲染场景,从主模拟线程中提取数据.这没有同步,并且工作正常.
问题是当程序退出时,渲染器需要停止从模拟线程中提取数据,然后模拟线程才能安全地自我清理,而不会导致渲染器尝试读取无效内存.
为了实现这一点,我让渲染器在其线程中无限运行:
volatile bool stillRendering;
void RenderThreadFunction()
{
stillRendering = true;
while(programRunning)
{
renderer->render();
}
stillRendering = false;
}
Run Code Online (Sandbox Code Playgroud)
在主程序线程中,当收到windproc退出消息时,我会:
void OnQuit()
{
programRunning = false;
while(stillRendering)
{
}
delete application;
}
Run Code Online (Sandbox Code Playgroud)
这样做的目的是确保渲染器在应用程序上调用delete之前停止从应用程序中提取数据.
我首先尝试了这个没有任何volatile关键字,并且它在调试模式下工作,但在发布模式下它挂了.我假设编译器进行了一些优化,导致程序停止检查stillRendering的值.
将volatile添加到stillRendering会导致应用程序在我到目前为止每次测试时成功退出.我不确定为什么"programRunning"不稳定似乎并不重要.
最后,我不确定如何使用volatile为"stillRendering"影响程序的性能.如果使用StillRendering volatile会影响OnQuit()的性能,那对我来说并不重要,但如果它影响RenderThreadFunction()的性能,它对我来说很重要
虽然它可能适用于某些编译器,但它完全不安全.基本上,volatile只影响它所附加的变量,因此RendererThreadFunction,例如,在完成
之前可以设置为
stillRenderingfalse .(这是正确的,即使两者
并均不稳定.)问题的probablility是非常小的,因此测试可能不会透露它.最后,VC++的一些版本不给
的原子访问的语义在C++ 11,在这种情况下,你的代码将工作.(当然,在使用不同版本的VC++编译之前.)renderer->render();stillRenderingprogramRunningvolatile
鉴于renderer->render()几乎肯定会花费不可忽略的时间,因此绝对没有理由不在此处使用条件变量.关于你volatile用于此类事情的唯一时间是关闭机制是否由信号触发(在这种情况下,类型将是sig_atomic_t,而不是bool,虽然在实践中,它可能没有任何区别).在这种情况下,不会有两个线程,只有渲染器线程和信号处理程序.
如果您希望您的代码适用于所有编译器中的所有体系结构,请使用C++ 11 atomics:
std::atomic<bool> stillRendering;
void RenderThreadFunction()
{
stillRendering = true;
while(programRunning)
{
renderer->render();
}
stillRendering = false;
}
Run Code Online (Sandbox Code Playgroud)
Volatile 不适用于多线程 - 标准实际上允许编译器volatile使用非volatile访问重新排序访问.VC++扩展了它volatile的功能集以防止重新排序,但是其他编译器没有,并且它可能会破坏那些编译器.
正如其他人所提到的那样,volatile也不会影响可见性,这意味着非缓存一致的体系结构可能永远不会看到标志集.x86甚至不会立即缓存一致(写入速度非常慢),因此当通过各种缓冲区发送写入时,程序将总是以超出应有的速度循环.
C++ 11原子避免了这两个问题.
好的,所以这主要是为了纠正你当前的代码并警告你不要滥用volatile.詹姆斯建议使用条件变量(这只是你正在做的更有效的版本)可能是最适合你的实际解决方案.
| 归档时间: |
|
| 查看次数: |
3349 次 |
| 最近记录: |