在C++,x86-64中读写线程安全的智能指针

Riz*_*zar 5 c++ x86 smart-pointers thread-safety lock-free

我开发了一些无锁数据结构,并出现以下问题.

我有编写器线程在堆上创建对象并使用引用计数器将它们包装在智能指针中.我也有很多读者线程,可以使用这些对象.代码可能如下所示:

SmartPtr ptr;

class Reader : public Thread {
    virtual void Run {
       for (;;) {
           SmartPtr local(ptr);
           // do smth   
       }
    }   
};

class Writer : public Thread {
    virtual void Run {
       for (;;) {
           SmartPtr newPtr(new Object);    
           ptr = newPtr;  
       }
    }
};

int main() {
    Pool* pool = SystemThreadPool();
    pool->Run(new Reader());
    pool->Run(new Writer());
    for (;;) // wait for crash :(
}
Run Code Online (Sandbox Code Playgroud)

当我创建它的线程局部副本ptr至少意味着

  1. 读一个地址.
  2. 增加参考计数器.

我无法原子地执行这两个操作,因此有时候我的读者会使用已删除的对象.

问题是 - 我应该使用什么样的智能指针来从几个线程进行读写访问,并且可以进行正确的内存管理?解决方案应该存在,因为Java程序员甚至不关心这样的问题,只是依赖于所有对象都是引用,并且只有在没有人使用它们时才会被删除.

对于PowerPC,我发现http://drdobbs.com/184401888,看起来不错,但使用了我们在x86中没有的Load-Linked和Store-Conditional指令.

据我所知,boost指针仅使用锁提供此类功能.我需要无锁解决方案.

ron*_*nag 9

boost :: shared_ptr有atomic_store,它使用一个"无锁"的自旋锁,对于99%的可能情况应该足够快.

    boost::shared_ptr<Object> ptr;
class Reader : public Thread {
    virtual void Run {
       for (;;) {
           boost::shared_ptr<Object> local(boost::atomic_load(&ptr));
           // do smth   
       }
    }   
};

class Writer : public Thread {
    virtual void Run {
       for (;;) {
           boost::shared_ptr<Object> newPtr(new Object);    
           boost::atomic_store(&ptr, newPtr);
       }
    }
};

int main() {
    Pool* pool = SystemThreadPool();
    pool->Run(new Reader());
    pool->Run(new Writer());
    for (;;)
}
Run Code Online (Sandbox Code Playgroud)

编辑:

在回应下面的评论时,实施是在"boost/shared_ptr.hpp"中......

template<class T> void atomic_store( shared_ptr<T> * p, shared_ptr<T> r )
{
    boost::detail::spinlock_pool<2>::scoped_lock lock( p );
    p->swap( r );
}

template<class T> shared_ptr<T> atomic_exchange( shared_ptr<T> * p, shared_ptr<T> r )
{
    boost::detail::spinlock & sp = boost::detail::spinlock_pool<2>::spinlock_for( p );

    sp.lock();
    p->swap( r );
    sp.unlock();

    return r; // return std::move( r )
}
Run Code Online (Sandbox Code Playgroud)