4

在 Boost 1.5.1 源代码下smart_ptr\detail\atomic_count_win32.hpp是一个整洁的小原子引用计数器boost::detail::atomic_count

在第 48 行,他们做了一个我很好奇的演员表:

class atomic_count
{
public:

// ...

operator long() const
{
    return static_cast<long const volatile &>( value_ );
}

private:
long value_;

为什么将计数器值转换为 a-reference-to-a-volatile-constant-long ( long const volatile&)?

4

2 回答 2

5

MSVC 提供了一个现已弃用variables扩展volatile,赋予它们获取和释放语义(内存排序保证,关于多线程编程。)

此强制转换“启用”变量上的此扩展,赋予它读取-获取语义(以匹配任何也可能发生的发布-写入)。同样,这是非标准的。在 C++11 代码中,您应该使用std::atomic<>.

他们需要这个,因为boost::shared_ptr它保证了shared_ptr<T>多线程(共享)使用的正确性;这是他们实现的无计数器。

(此外,这只是故事的一半:虽然此扩展可能提供所需的顺序和可见性保证,但它不保证原子性。在 Win32 上,这由它运行的平台隐式保证:对齐的字大小整数读取和写入是每个平台都是原子的。)

在它开始之前将它扼杀在萌芽状态:没有这个扩展volatile对多线程编程没有用处。甚至不要尝试。此扩展已被弃用,因此您应该尽可能避免使用它。

于 2012-12-03T20:18:14.913 回答
1

在 x86 平台上,对于原生宽度的对齐值,这已经足够了。

他们试图避免的问题是:

  1. 该变量具有十六进制值0000FFFF

  2. 线程 A 开始读取值并获取0000xxxx零件。

  3. 线程 B 将值从0000FFFF增加到00010000

  4. 线程 A 完成读取值,得到xxxx0000它尚未读取的部分。

  5. 线程 A 现在读取的值为00000000!

这称为字撕裂。但是,众所周知,这不会发生在 x86 上对齐的原生宽度类型中。因此,只需进行一次强制volatile转换(众所周知,这可以避免有问题的编译器优化)。

请注意,这不是一些普遍的事实。这恰好是平台的属性。这不是可移植的代码。

于 2012-12-03T20:17:20.447 回答