在boost::shared_ptr
析构函数中,完成了:
if(--*pn == 0)
{
boost::checked_delete(px);
delete pn;
}
其中pn
是指向引用计数器的指针,其类型定义为
shared_ptr::count_type -> detail::atomic_count -> long
我希望long
为volatile long
,给定线程用法以及上面shared_ptr
析构函数中的非原子0检查和删除。为什么它不稳定?
编辑:
事实证明,我查看了未指定多线程使用时使用的标头(atomic_count.hpp)。在atomic_count_win32.hpp中,为多线程用法正确实现了减量。
答案 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.hpp
或boost/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