为什么boost :: shared_ptr中的引用计数器不是volatile?

时间:2010-03-26 11:02:28

标签: c++ multithreading boost shared-ptr

boost::shared_ptr析构函数中,完成了:

if(--*pn == 0)
{
    boost::checked_delete(px);
    delete pn;
}

其中pn是指向引用计数器的指针,其类型定义为

shared_ptr::count_type -> detail::atomic_count -> long

我希望longvolatile long,给定线程用法以及上面shared_ptr析构函数中的非原子0检查和删除。为什么它不稳定?

编辑:

事实证明,我查看了未指定多线程使用时使用的标头(atomic_count.hpp)。在atomic_count_win32.hpp中,为多线程用法正确实现了减量。

3 个答案:

答案 0 :(得分:16)

因为多线程不需要volatile,并且没有任何好处,但可能会破坏许多优化。

为了确保对变量的安全多线程访问,我们需要的原语是一个内存屏障,它提供volatile和其他几个的保证(它阻止内存访问重新排序跨越障碍,哪个是volatile不这样做)

我相信shared_ptr尽可能使用原子操作,这隐含地提供了内存屏障。否则它会回落到互斥锁,这也会提供内存屏障。

有关详细信息,请参阅Why is volatile not considered useful in multithreaded C or C++ programming?http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/

修改
在一般情况下,count_type 一个long。它是可转换long。如果查看atomic_count.hpp,只有在没有可用线程的情况下才会应用typedef to long(在这种情况下,当然不需要同步)。否则,它使用boost/smart_ptr/detail/atomic_count_pthreads.hppboost/smart_ptr/detail/atomic_count_win32.hpp中定义的实现或列出的其他文件之一。这些是同步的包装类,确保所有操作都是原子化的。

答案 1 :(得分:8)

volatile几乎与线程无关。请参阅here

答案 2 :(得分:2)

您误读了代码。如果代码不使用多线程,则atomic_count被定义为long:

#ifndef BOOST_HAS_THREADS

namespace boost
{

namespace detail
{

typedef long atomic_count;

}

}

#elif //... include various platform-specific headers that define atomic_count class

#endif