简体   繁体   English

使用原子的线程安全 singleton

[英]Thread-safe singleton using atomic

Just want to know whether atomic_flag = 1;只想知道atomic_flag = 1; keeps the myclass_st assignment thread-safe or not.保持 myclass_st 分配线程安全与否。 (I am sorry that my example has so many problems, so I have changed it.) (对不起,我的例子有这么多问题,所以我改了。)

myClass* myclass_st = nullptr;
std::atomic<int> atomic_flag;
std::mutex mtx; //err
myClass* get_instance() {
    
    //std::unique_lock<std::mutex> lk(mtx);
    if (myclass_st == nullptr) {
        mtx.lock();
        if (myclass_st == nullptr) {
            myclass_st = new myClass();
            atomic_flag = 1;
            mtx.unlock(); //err
        }
    }
    return myclass_st;
}

I know we can use static after c11.我知道我们可以在 c11 之后使用static

Maybe I should modify the code like this?也许我应该像这样修改代码?

myClass* myclass_st = nullptr;
std::atomic<int> atomic_flag;
myClass* get_instance() {

    if (atomic_flag.load() == 0) {
        std::unique_guard<std::mutex> lk(mtx);
        if (atomic_flag.load() == 0) {
            myclass_st = new myClass();
            atomic_flag = 1;
        }
    }
    return myclass_st;
}

The shown code is not threaded save, because std::mutex mtx;显示的代码不是线程保存的,因为std::mutex mtx; is a new object each time.每次都是新的 object。 The std::mutex mtx; std::mutex mtx; has to be static so that it is the same mutex for each invocation of get_instance` but even then the manual locking and unlocking of the mutex would not be valid in the current form.必须是static so that it is the same mutex for each invocation of但即便如此,手动锁定和解锁互斥锁在当前形式下也无效。

EDIT after moving the std::mutex mtx;移动std::mutex mtx;编辑 out of the function the mutex is the same for each invocation of get_instance .在 function 中,每次调用get_instance的互斥锁都是相同的。 But it is still not threaded save.但它仍然不是线程保存。 Multiple threads could pass the first if (myclass_st == nullptr) { condition where myclass_st is nullptr .多个线程可以通过第一个if (myclass_st == nullptr) { myclass_stnullptr的条件。 If there are eg more then three threads that pass the first if then the thread that first calls lock will set myclass_st and release its lock on the mutex.如果有例如超过三个线程通过第一个if那么第一个调用lock的线程将设置myclass_st并释放它在互斥锁上的锁。 The second thread that called lock won't release its acquired lock, so all other threads that passed the first if are blocked.第二个调用lock的线程不会释放它获得的锁,因此所有其他通过第一个if的线程都被阻塞。

It has to be either:它必须是:

myClass* get_instance() {
    mtx.lock();
    if (myclass_st == nullptr) {
      myclass_st = new myClass();
      atomic_flag = 1;
    }
    mtx.unlock();
    return myclass_st;
}

Instead of manually locking and unlocking you normally want to do the locking with a lock guard with automatic storage duration (RAII idiom), because that ensures that the lock on the mutex is always released when get_instance is left.您通常不想手动锁定和解锁,而是使用具有自动存储持续时间(RAII 习惯用法)的锁守卫进行锁定,因为这样可以确保在离开get_instance时始终释放互斥锁上的锁。

myClass* get_instance() {
    std::lock_guard<std::mutex> lk(mtx);
    if (myclass_st == nullptr) {
      myclass_st = new myClass();
      atomic_flag = 1;
    }
    return myclass_st;
}

EDIT No neither the first nor the second example is thread save.编辑不,第一个和第二个示例都不是线程保存。 For the second example as you show it the if (atomic_flag.load() == 0) { /**... **/ atomic_flag = 1;} could still be entered by two threads.对于您展示的第二个示例, if (atomic_flag.load() == 0) { /**... **/ atomic_flag = 1;}仍然可以由两个线程输入。 So new myClass could still be done multiple times.所以new myClass仍然可以多次完成。

Just want to know whether atomic_flag = 1;只想知道 atomic_flag = 1; keeps the myclass_st assignment thread-safe or not.保持 myclass_st 分配线程安全与否。

No.不。

Maybe I should modify the code like this?也许我应该像这样修改代码?

 myClass* myclass_st = nullptr; std::atomic<int> atomic_flag; myClass* get_instance() { if (atomic_flag.load() == 0) { myclass_st = new myClass(); atomic_flag = 1; } return myclass_st; }

If you intent get_instance to be called by multiple threads, then no.如果您打算让多个线程调用get_instance ,那么不会。

I guess you want:我猜你想要:

myClass* myclass_st = nullptr;
std::atomic<int> atomic_flag{0};
std::mutex mtx;
myClass* get_instance() {
    if (atomic_flag == 0) {
        std::unique_lock<std::mutex> lk(mtx);
        if (myclass_st == nullptr) {
            myclass_st = new myClass();
            atomic_flag = 1;
        }
    }
    return myclass_st;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM