Is the next oneton implementation thread safe?

Is the next oneton implementation thread safe? The :: Instance method must be correct, Dispose is my own creation, so I want to make sure that I have not forgotten anything.

std::atomic<S *> S::_instance;
std::mutex S::_singleton_mutex;

S& S::Instance()
{
    using namespace std;
    S * tmp = _instance.load(memory_order_relaxed);
    atomic_thread_fence(memory_order_acquire);
    if (tmp == nullptr)
    {
        lock_guard<mutex> l(_singleton_mutex);
        tmp = _instance.load(memory_order_relaxed);
        if (tmp == nullptr)
        {
            tmp = new S();
            atomic_thread_fence(memory_order_release);
            _instance.store(tmp, memory_order_relaxed);
    }
    return *tmp;
}

void S::Dispose()
{
    using namespace std;
    S * tmp = _instance.load(memory_order_relaxed);
    atomic_thread_fence(memory_order_acquire);
    if (tmp != nullptr)
    {
        lock_guard<mutex> l(_singleton_mutex);
        tmp = _instance.load(memory_order_relaxed);
        if (tmp != nullptr)
        {
            atomic_thread_fence(memory_order_release);
            _instance.store(nullptr, memory_order_relaxed);
            delete tmp;
        }
    }
}
+4
source share
2 answers

Solution: Yes, it looks good.

Additional Information:

If it is acceptable for you to potentially have two instances for a short period of time, where the second will be immediately destroyed, you can get rid of the mutex:

std::atomic<S *> S::_instance;

S& S::Instance()
{
    using namespace std;
    auto tmp = _instance.load(memory_order_relaxed);
    if (tmp == nullptr)
    {
        auto tmp2 = new S();
        if( !_instance.compare_exchange_strong(tmp, tmp2) )
            delete tmp2;
    }
    return *tmp;
}

void S::Dispose()
{
    using namespace std;
    auto tmp = _instance.load(memory_order_relaxed);
    if (tmp != nullptr)
    {
        if( _instance.compare_exchange_strong(tmp, nullptr) )
            delete tmp;
    }
}

(), a nullptr S. , S.

, Scott Meyers, :

S& S::Instance() 
{
    // This instance will be created at first call - thread safe.
    // it lives until the program terminates.
    static Singleton instance;
    return instance;
}

, , btw.

+2

, . : .

Thread A: var i = s::Instance();
Thread B: s::Dispose();
Thread A: i.doSth();

, , ; , .

+1

Source: https://habr.com/ru/post/1615205/


All Articles