C++:多线程和refcounted对象

Ste*_*ury 7 c++ multithreading refcounting

我目前正在尝试将单线程程序传递给多线程.该软件大量使用"refCounted"对象,这导致多线程中的一些问题.我正在寻找一些可能解决我的问题的设计模式.

主要问题是线程之间的对象删除,通常删除只减少引用计数,当refcount等于零时,则删除对象.这在monothread程序中运行良好,并且可以通过大对象的副本实现一些很好的性能提升.

但是,在多线程中,两个线程可能希望同时删除同一个对象,因为该对象受互斥锁保护,只有一个线程删除该对象并阻塞另一个.但是当它释放互斥锁时,另一个线程继续执行无效(释放对象),这会导致内存损坏.

以下是此类RefCountedObject的示例

class RefCountedObject
{
public:
RefCountedObject()
:   _refCount( new U32(1) )
{}

RefCountedObject( const RefCountedObject& obj )
:   _refCount( obj._refCount )
{
    ACE_Guard< ACE_Mutex > guard( _refCountMutex );
    ++(*_refCount);
}

~RefCountedObject()
{
    Destroy();
}

RefCountedObject& operator=( const RefCountedObject& obj )
{
    if( this != &obj )
    {
        Destroy();
        ACE_Guard< ACE_Mutex > guard( _refCountMutex );
        _refCount = obj._refCount;
        ++(*_refCount);
    }

    return *this;
}

private:
    void Destroy()
    {
        ACE_Guard< ACE_Mutex > guard( _refCountMutex );  // thread2 are waiting here
        --(*_refCount);         // This cause a free memory write by the thread2
        if( 0 == *_refCount )
            delete _refCount;
    }

private:
    mutable U32* _refCount;
    mutable ACE_Mutex _refCountMutex; // BAD: this mutex only protect the refCount pointer, not the refCount itself
};
Run Code Online (Sandbox Code Playgroud)

假设两个线程想要删除相同的RefCountedObject,两者都在~RefCountedObject中并调用Destroy(),第一个线程锁定了互斥锁,另一个线程正在等待.在第一个线程删除对象之后,第二个线程将继续执行并导致空闲内存写入.

任何人都有类似问题的经验,并找到了解决方案?


感谢大家的帮助,我意识到自己的错误:互斥锁只是保护refCount指针,而不是refCount本身!我创建了一个受互斥保护的RefCount类.现在,所有refCounted对象之间共享互斥锁.

现在一切正常.

Ant*_*ams 4

如果计数是对象的一部分,那么如果一个线程可能尝试增加引用计数,而另一个线程尝试删除最后一个引用,那么您就会遇到一个固有的问题。对于每个可全局访问的对象指针,引用计数上需要有一个额外的值,因此,如果您有指针,则始终可以安全地增加引用计数。

一种选择是使用boost::shared_ptr (请参阅文档)。您可以使用自由函数atomic_loadatomic_storeatomic_exchangeatomic_compare_exchange文档中明显没有这些函数)来确保在访问共享对象的全局指针时得到适当的保护。一旦您的线程获得了shared_ptr对特定对象的引用,您就可以使用普通的非原子函数来访问它。

另一种选择是使用 Joe Seigh 的atomic_ptr_plus 项目中的原子引用计数指针