在smart_ptr\detail\atomic_count_win32.hpp
下的Boost 1.5.1源代码中,它是一个简洁的小原子参考计数器boost::detail::atomic_count
。
class atomic_count
{
public:
// ...
operator long() const
{
return static_cast<long const volatile &>( value_ );
}
private:
long value_;
为什么计数器值会转换为--to-volatile-constant-long(long const volatile&
)?
答案 0 :(得分:5)
MSVC提供了一个现已弃用的extension on volatile
variables,给予它们获取和释放语义(关于多线程编程的内存排序保证。)
此演员“在变量上启用”此扩展,为其提供读取 - 获取语义(以匹配可能还会发生的任何释放写入)。同样,这是非标准。在C ++ 11代码中,您应该使用std::atomic<>
。
他们需要这个,因为boost::shared_ptr
可以保证多线程(共享)使用中shared_ptr<T>
的正确性;这是他们对lock-free计数器的实现。
(另外,这只是故事的一半:虽然这个扩展可能提供所需的排序和可见性保证,但它不保证原子性。在Win32上,它运行的平台隐含地保证:对齐的字大小的整数读取并且每个平台的写入都是原子的。)
要在它开始之前将它扼杀在萌芽状态:没有此扩展名volatile
对多线程编程没有用。甚至不尝试。这个扩展名已弃用,所以如果可以,你应该真的避免使用它。
答案 1 :(得分:1)
在x86平台上,对于原生宽度的对齐值,已知这已足够。
他们试图避免的问题是:
变量的十六进制值为0000FFFF
。
线程A开始读取值并获取0000xxxx
部分。
主题B将值从0000FFFF
增加到00010000
。
线程A完成读取值,获取尚未读取的xxxx0000
部分。
线程A现在读取的值为00000000
!
这称为单词撕裂。但是,众所周知,x86上的对齐类型的原生宽度不会发生这种情况。因此,只需要通过volatile
(已知可避免有问题的编译器优化)进行强制转换。
请注意,这不是一般的事实。这恰好是平台的一个属性。这不是可移植的代码。