我对使用多个线程的对象有疑问.
首先,使用std :: lock_guard或其他方式保护对象不会同时访问是没有问题的.
下一步是使用volatile声明对象.
class A{ public: int val;};volatile A a;
但这样做最终会导致很多新函数的类型限定符不稳定
…
int GetVal()volatile;
void SetVal()volatile;
…
好的,这一切都很好.
但是如何访问stl成员,例如std :: vector或std :: map.
如果我想要一个volatile std :: vector< int>我运行了很多错误,而stl没有定义任何volatile方法.
从这一点开始,我在网上搜索了很多“技巧”.在后台主要有相同的想法:拥有一个用于并发保护的互斥锁,并使用const_cast移动volatile以使标准接口可用.
作为此实现的示例:
template <typename T>class PseudoPtr { public: PseudoPtr(volatile T& obj, mutex& mtx) : guard(mtx), pObj_(const_cast<T*>(&obj)) { } ~PseudoPtr() { } // Pointer behaviour T& operator*() { return *pObj_; } T* operator->() { return pObj_; } private: my_guard<mutex> guard; T* pObj_; PseudoPtr(const PseudoPtr&) = delete; PseudoPtr& operator=(PseudoPtr &) = delete;};
从上面得到我的示例类没有volatile限定符:
class A { ... int GetVal(); };
但是,如果我以下列方式使用它:
volatile A a; mutex mu; ... for (;;) { PseudoPtr ptr(a, mu); //starts locking the object if (ptr->GetVal()) { ... do something ... } }
我永远不会在对象a中看到任何变化,因为编译器可以进行优化
访问,因为volatile对象是const_cast,所以优化器没有
了解挥发性行为.
对于我自己的所有类,这不是问题,而我可以编写所有volatile方法.但是如果我想使用stl容器,就没有办法从它们那里获得volatile实例并通过const_cast使用它.
好的,实际的编译器并不是那么难以优化(gcc 4.6.1),但有保证编译器永远不会进行这种优化吗? const_cast将破坏volatile并且不会对volatile stl对象进行const_cast,因为stl容器根本没有volatile方法.
我认为,网上发现的所有“技巧”都是错误的,因为它们都忽略了
优化.
这在我的问题中运行:
>我对volatile和优化器的解释错了吗?
>对于使用stl conatiner线程安全,是否有“标准”工作解决方案?
———————-经过几个小时的阅读———————- –
首先,是的,pthread_mutex_lock应该执行以下操作:*访问内存原子(这是我之前唯一知道的事情)*保证内存对所有其他线程可见
好的,第二个对我来说是新的!这导致了下一个问题:这个技巧如何运作?
提供互斥语义的库必须有机会告诉编译器,停止乱序执行*将所有缓存(寄存器优化)变量写入硬件*告诉硬件同步所有硬件缓存等.
好的!但是它是如何工作的:特定于gcc的实现:存在一个名为barrier()的宏,就像这样
asm volatile(“”:::“memory”);
gcc的pthread库包含在glibc / nptl中,每个保证数据可见性到其他线程的函数只需调用barrier宏或直接调用内联汇编程序或用类似的东西做事.
如果再没有误会,这就是幕后的简单事情.
我学到的东西:与互斥锁相结合的volatile在任何情况下都没有意义.
我写下这个答案,希望其他人能够在那个神秘面前变得更加沉闷.
如果再次出现错误和误解?!:让我知道!
谢谢你的所有答案!
(很抱歉编辑我的帖子来添加我自己的结论,但我无法在帖子中添加自己的答案)
解决方法:
如果您正在使用互斥锁等来同步对对象的访问,请执行you don’t need volatile
at all.
联系客服