Poco RefCountedObject提供2个接口:
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是原子的,但如果(--_ count)不是原子的,可能会导致对已删除对象的引用。 例如,假设我有2个线程A和B一个执行重复,另一个版本执行,执行顺序如下:
我们最终得到A有一个被删除对象的引用。 即使mutable关键字强制编译器不优化_counter它也不会帮助多线程
我错过了什么吗?
答案 0 :(得分:1)
严格地看待重复并单独发布,以上是正确的。
但是,如果你有两个线程,都有一个指向同一个RefCountedObject的指针,你应该在每个线程中有单独的AutoPtr实例(这意味着_counter是> 1开始),或者,如果你共享如果至少有一个线程可以更改AutoPtr(这将导致调用release()),则必须使用互斥锁保护相同的AutoPtr。毋庸置疑,在多个线程之间共享可变AutoPtr是一种灾难。
如果你通过手动调用duplicate()和release()来管理RefCountedObject(我不推荐),你应该遵循POCO的引用计数规则并且要非常小心。
因此,对于性能良好的代码,RefCountedObject和AutoPtr对于多线程使用是安全的。
答案 1 :(得分:0)
这是安全的,因为计数器基于 std::atomic
AND std::atomic
默认使用 std::memory_order_seq_cst
进行操作。
如果 std::atomic
正在使用 std::memory_order_relaxed
,那么实现将有问题/不安全。
缺点是 std::memory_order_seq_cst
是“慢”的。有比 Poco 更快的实现,但不那么简单,通过使用一些不同的代码和不同的内存排序命令 (https://en.cppreference.com/w/cpp/atomic/memory_order)