Poco RefCountedObject 提供 2 个接口(interface):
inline void RefCountedObject::duplicate() const
{
++_counter;
}
inline void RefCountedObject::release() const throw()
{
try
{
if (--_counter == 0) delete this;
}
catch (...)
{
poco_unexpected();
}
}
与:
class Foundation_API RefCountedObject
/// A base class for objects that employ
/// reference counting based garbage collection.
///
/// Reference-counted objects inhibit construction
/// by copying and assignment.
{
public:
RefCountedObject();
/// Creates the RefCountedObject.
/// The initial reference count is one.
void duplicate() const;
/// Increments the object's reference count.
void release() const throw();
/// Decrements the object's reference count
/// and deletes the object if the count
/// reaches zero.
int referenceCount() const;
/// Returns the reference count.
protected:
virtual ~RefCountedObject();
/// Destroys the RefCountedObject.
private:
RefCountedObject(const RefCountedObject&);
RefCountedObject& operator = (const RefCountedObject&);
mutable AtomicCounter _counter;
};
请注意: 可变的 AtomicCounter _counter;
我的问题是如果我在多线程中使用 RefCountedObject 是否安全?
在我看来,这并不是因为只有 --_counter 是原子的,而 if(--_count) 不是原子的,并且可能导致引用已删除的对象。 例如假设我有 2 个线程 A 和 B,一个执行复制,另一个执行释放,执行顺序如下:
- B开始执行release并到达--_counter
- A开始执行duplicate并到达++_counter
- 此时_counter=1
- B 执行 --_counter 并返回 if 评估的结果(即 0 && counter 现在为 0)
- B 被抢占并在分支语句(if)之前停止
- A 执行 _counter++ 并返回对象的引用
- B 继续计算值为 0 的分支语句并删除对象
我们最终得到 A 引用了一个已删除的对象。 即使 mutable 关键字强制编译器不优化 _counter,它也无助于多线程
我错过了什么吗?
最佳答案
严格孤立地看重复和发布,以上是正确的。
但是,如果您有两个线程,它们都有一个指向同一个 RefCountedObject 的指针,那么您应该在每个线程中有单独的 AutoPtr 实例(这意味着开始时 _counter > 1),或者,如果您共享相同的AutoPtr,如果至少有一个线程可以更改 AutoPtr(这将导致调用 release()),则它必须由互斥体保护。不用说,在多个线程之间共享一个可变的 AutoPtr 是灾难的根源。
如果您通过手动调用 duplicate() 和 release() 来管理 RefCountedObject(我不推荐这样做),您应该遵循 POCO 的引用计数规则并非常小心。
因此,对于行为良好的代码,RefCountedObject 和 AutoPtr 对于多线程使用是安全的。
关于c++ - Poco RefCountedObject 线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38749500/