如果有两个线程访问全局变量,那么许多教程都说使变量volatile变为阻止编译器将变量缓存在寄存器中,从而无法正确更新.但是,访问共享变量的两个线程是通过互斥锁来调用保护的东西不是吗?但是在这种情况下,在线程锁定和释放互斥锁之间,代码处于一个关键部分,只有那个线程可以访问变量,在这种情况下变量不需要是volatile?
那么多线程程序中volatile的用途/目的是什么?
我正在编写一个程序,其中一个进程读取和写入共享内存,另一个进程只读取它.在共享内存中有一个这样的结构:
struct A{
int a;
int b;
double c;
};
我期望的是立刻读取结构,因为在我阅读时,其他进程可能正在修改结构的内容.如果结构赋值是原子的,那么可以实现这一点,而不是中断.像这样:
struct A r = shared_struct;
那么,C/C++中的struct assignment atomic是什么?我尝试在网上搜索但找不到有用的答案.有人可以帮忙吗?谢谢.
我使用经过检查的STL实现在我的代码中有意外的断言故障.
经过一些研究后,我将问题缩小到一个向量中的push_back,该向量来自与创建向量的线程不同的线程.
重现此问题的最简单代码是:
class SomeClass
{
private:
std::vector<int> theVector;
public:
SomeClass ()
{
theVector.push_back(1); // Ok
}
void add()
{
theVector.push_back(1); // Crash
}
};
Run Code Online (Sandbox Code Playgroud)
唯一的区别是SomeClass是从我的主线程实现的,而add是从另一个线程调用的.然而,没有一个简洁的问题:在我用于排除故障的最简单的代码形式中,除了我上面提到的情况之外,没有人从这个向量中读取或写入.
跟踪push_back代码,我注意到std :: vector中的一些方法如count()或size()返回垃圾,当从另一个thred(方法"add")调用时,从创建线程调用时返回正确的值(例如在构造函数中)
我应该得出结论,std :: vector在多线程环境中不可用吗?或者是否有解决此问题的方法?
编辑:删除volatile
编辑2:你认为这个问题可能不在于多线程吗?在我的测试运行中,add只被调用一次(使用断点验证).如果我从构造函数中删除push_back,我仍然会崩溃.所以最后,即使只调用一个向量的方法,在一次调用的函数中也会使断言失败.因此,不能有可靠性,或......?
在进行并发编程时,我需要告诉编译器/优化器它可能不会缓存变量的值,也就是说,它可能随时改变.我目前正在使用volatile关键字,但我想知道这是否真的正确?
该标准规定易失性访问可能不会重新排序,如IO调用,但我实际上根本不关心排序,我关心内容.标准中是否有任何内容可以澄清每次访问时都必须加载volatile ?
更重要的是,在这种情况下,我甚至不关心它是否重新排序.我使用栅栏/原子操作来保证我需要的任何订单.
另外,在C++ 0x中,将使用atomic<T>自动给出相同的加载保证(如果我调用load)?或者我是否必须将变量标记为volatile?
重要我对锁定一段代码不感兴趣.我已经使用栅栏来确保订购.我正在谈论对单个基础的访问int(在我正在的平台上假设原子).也就是说,我需要专门告诉GCC优化器a不应该以任何方式缓存变量,因此如果在循环中使用,则必须每次都调用相应的加载指令.
如果volatile不正确,这样做的正确方法是什么?我目前正在使用GCC而不是使用C++ 0x.
答案:基本上预先C++ 0x没有什么可以强制重新加载,并且在某些架构上重新加载甚至可能不够.volatile强烈暗示变量应该重新加载,并且可以在许多体系结构上工作,虽然不是正确的答案,但是目前唯一可用的选项.
关于volatile的问题已经有很多了,但是我没有看到一个特别针对我要问的问题:为并发访问标记变量的正确方法.
可能重复:
何时使用volatile多线程?
我有两个引用相同的线程boost::shared_ptr:
boost::shared_ptr<Widget> shared;
Run Code Online (Sandbox Code Playgroud)
在线程正在旋转,等待另一个线程重置boost::shared_ptr:
while(shared)
boost::thread::yield();
Run Code Online (Sandbox Code Playgroud)
在某些时候,另一个线程会调用:
shared.reset();
Run Code Online (Sandbox Code Playgroud)
我的问题是我是否需要声明共享指针volatile以防止编译器优化shared.operator bool()对循环的调用并且从不检测更改?我知道如果我只是循环变量,等待它达到0我需要volatile,但我不确定是否boost::shared_ptr以这样的方式实现它是不必要的.
编辑:我完全清楚条件变量可以用来以不同的方式解决这个问题.但在这种情况下,繁忙的循环非常罕见,并且争用条件变量的锁定是我们宁愿不会产生的开销.