【发布时间】:2012-09-14 16:18:44
【问题描述】:
我正在努力思考如何确保对象引用计数是线程安全的。
class MyObject{
//Other implementation details
private:
mutable volatile LONGLONG * m_count;
IData * m_data;
};
假设有必要的类声明,保持简单。下面是拷贝构造函数和析构函数的实现。
MyObject::MyObject(const MyObject& rhs) : m_count(rhs.m_count), m_data(rhs.m_data){
InterlockedIncrement64(m_count);
}
MyObject::~MyObject(){
if(InterlockedDecrement64(m_count) == 0)
delete m_data;
}
这个线程安全吗?复制构造函数的 intilization 列表是如何看到的,原子的还是非原子的?这还重要吗?我应该在初始化列表中设置计数的递增值(这可能吗)?
就目前而言,这已经足够好了。我在想,否则,我怎么会遇到thread1 正在复制而thread2 正在同时销毁count == 1 的情况。线程之间必须进行握手,这意味着线程 1 必须在线程 2 的对象超出范围之前完全复制对象,对吗?
在阅读了其中一些回复后,我回去做了一些研究。 Boost 非常相似地实现了它们的 shared_ptr。这是析构函数调用。
void release() // nothrow
{
if( BOOST_INTERLOCKED_DECREMENT( &use_count_ ) == 0 )
{
dispose();
weak_release();
}
}
有些人建议在 boost 文档中明确指出分配不是线程安全的。我同意和不同意。我认为在我的情况下我不同意。我只需要threadA和threadB之间的握手。我认为某些回复中描述的某些问题在这里并不适用(尽管它们是我没有完全考虑透彻的令人大开眼界的回复)。
示例 线程A 附加(共享对象); //通过值传递的共享对象,计数递增等。
线程B //接受对象,将其添加到共享对象列表中。 ThreadB 位于一个计时器上,该计时器向所有 SharedObjects 通知一个事件。在通知之前,列表的副本由关键部分保护。 CS发布,副本通知。
线程A 分离(共享对象); //从对象列表中删除共享对象
现在,ThreadB 正在同时对 SharedOjbect 进行单选,并且在 ThreadA 分离所述共享对象之前已经制作了列表的副本。一切都好吗?
【问题讨论】:
-
为什么是 64 位引用计数?你确定你没有过度设计这个吗?
-
如果你只是想保护柜台,你可以看看
std::atomic,如果你想要更广泛的保护,你可以看看std::mutex。 -
我没有发现代码有任何问题。
标签: c++ copy-constructor atomic interlocked-increment