Poco RefCountedObject 线程安全吗?

Is Poco RefCountedObject thread safe?

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;
};

注意: mutable AtomicCounter _counter;

我的问题是如果我在多线程中使用 RefCountedObject 是否安全?

在我看来,这并不是因为只有 --_counter 是原子的,而是 if(--_count) 不是原子的,并且可能导致引用已删除的对象。 例如假设我有 2 个线程 A 和 B,一个执行复制,另一个执行释放,执行顺序如下:

我们最终得到 A 对已删除对象的引用。 即使 mutable 关键字强制编译器不优化 _counter 它也无助于多线程

我错过了什么吗?

严格孤立地查看复制和发布,以上是正确的。

但是,如果您有两个线程,都具有指向同一个 RefCountedObject 的指针,则您应该在每个线程中有单独的 AutoPtr 实例(这意味着开始时 _counter > 1),或者,如果您共享相同的 AutoPtr,如果至少有一个线程可以更改 AutoPtr(这将导致调用 release()),则它必须由互斥锁保护。不用说在多个线程之间共享一个可变的 AutoPtr 是灾难的根源。

如果您通过手动调用duplicate() 和release() 来管理RefCountedObject(我不推荐这样做),您应该遵循POCO 的引用计数规则并非常小心。

因此,对于行为良好的代码,RefCountedObject 与 AutoPtr 一起用于多线程使用是安全的。

这是安全的,因为计数器基于 std::atomic AND std::atomic 默认使用 std::memory_order_seq_cst 进行操作。 如果 std::atomic 使用 std::memory_order_relaxed,那么实现将是 buggy/unsafe。 缺点是 std::memory_order_seq_cst 很“慢”。通过使用一些不同的代码和不同的内存排序命令 (https://en.cppreference.com/w/cpp/atomic/memory_order)

,有比 Poco 更快的实现,但不那么简单