vendredi 22 juillet 2016

Thread-safe intrusive_ptr

The boost::intrusive_ptr (or a home-made version) at its simplest looks like this:

template<typename T>
class intrusive_ptr {
public:
    intrusive_ptr(T* ptr) : ptr_(ptr)
    {
        if (ptr_) {
            intrusive_ptr_add_ref(ptr_);
        }
    }

    intrusive_ptr(const intrusive_ptr& that) : ptr_(that.ptr_)
    {
        if (ptr_) {
            intrusive_ptr_add_ref(ptr_);
        }
    }

    ~intrusive_ptr()
    {
        if (ptr_) {
            intrusive_ptr_release(ptr_);
        }
    }

    // ...

private:
    ptr_;
};

Usage:

class Foo {
public:
    // ...

private:
    std::size_t refcount_;

    friend void intrusive_ptr_add_ref(const Foo* p)
    {
        ++p->refcount_;
    }

    friend void intrusive_ptr_release(const Foo* p)
    {
        if (--p->refcount_ == 0) {  // line 1
            delete p;               // line 2
        }
    }
};

intrusive_ptr<Foo> p(new Foo);

Apparently as Foo is implemented now, intrusive_ptr<Foo>s aren't thread-safe. Simply changing the type of Foo::refcount_ to std::atomic<std::size_t> won't suffice either, because when one thread is between line 1 and line 2, another thread may try to increase the reference count.

So my question is: Is it possible to make intrusive_ptr thread-safe, ideally without resorting to heavy mechanisms like mutexes?

Aucun commentaire:

Enregistrer un commentaire