Does this redeem a thread-safe Double-Checked Locking pattern?

雨燕双飞 提交于 2019-12-24 04:52:15

问题


The problems with the original Double-Checked Locking pattern have been well-documented: C++ and the Perils of Double-Checked Locking. I have seen the topic come up in questions on SO fairly often.

I have come up with a version that, to me, seems to solve the race condition problem of the original pattern, but does it look ok to you?

In the code below, I assume that LOCK is a properly implemented mutex type that causes a memory barrier at it's lock/unlock, and I don't attempt to deal with the deallocation of the instance, as that's not part of the pattern.

I am aware of the other possible ways to do a singleton, but that's not what I am asking for. I am specifically asking about the pattern - is the race condition solved by having the allocation outside of the mutex lock?.

template <typename T, typename LOCK>
class Singleton
{
private:
    static T * instance_;
    static LOCK mutex;

    // private - inaccessible
    Singleton();
    Singleton(const Singleton &);
    Singleton & operator=(const Singleton &);

public:
    static T * get_instance()
    {
        if (instance_ == NULL)
        {
            T * temp = new T;
            mutex.lock();
            if (instance_ == NULL)
                instance = temp;
            else
                delete temp;
            mutex.unlock();
        }
        return instance_;
    }
};

回答1:


No this is not safe. There is a race condition on instance_ (one thread could be reading from it (if (instance_ == NULL)) while another is writing to it (instance = temp;)), so this code has undefined behaviour.

You are asking if the single memory fence created by the lock is sufficient. From the perspective of C++11, it is not. From a non-C++11 perspective, I can't say for sure, but relying on non-atomic and non-mutex types for synchronization seems unlikely to work (in the pre-C++11 world, mutexes and atomic variables only work through compiler and processor specific hacks, and it seems foolish to rely on them to do anything more than their bare specification).




回答2:


The problem, as has been mentioned elsewhere, is that there is a data race on accesses to instance_: the first if statement reads the value, and the later assignment to instance_ writes to that variable. With no synchronization between these two operations, the behavior is undefined. But there's an easy solution if you have C++11. Change the declaration

static T * instance_;

to

static std::atomic<T *> instance_;

Now all the accesses of instance_ are atomic, which guarantees no tearing and provides synchronization.



来源:https://stackoverflow.com/questions/12128706/does-this-redeem-a-thread-safe-double-checked-locking-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!