繁体   English   中英

使用原子的线程安全 singleton

[英]Thread-safe singleton using atomic

只想知道atomic_flag = 1; 保持 myclass_st 分配线程安全与否。 (对不起,我的例子有这么多问题,所以我改了。)

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;
}

我知道我们可以在 c11 之后使用static

也许我应该像这样修改代码?

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;
}

显示的代码不是线程保存的,因为std::mutex mtx; 每次都是新的 object。 std::mutex mtx; 必须是static so that it is the same mutex for each invocation of但即便如此,手动锁定和解锁互斥锁在当前形式下也无效。

移动std::mutex mtx;编辑 在 function 中,每次调用get_instance的互斥锁都是相同的。 但它仍然不是线程保存。 多个线程可以通过第一个if (myclass_st == nullptr) { myclass_stnullptr的条件。 如果有例如超过三个线程通过第一个if那么第一个调用lock的线程将设置myclass_st并释放它在互斥锁上的锁。 第二个调用lock的线程不会释放它获得的锁,因此所有其他通过第一个if的线程都被阻塞。

它必须是:

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

您通常不想手动锁定和解锁,而是使用具有自动存储持续时间(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;
}

编辑不,第一个和第二个示例都不是线程保存。 对于您展示的第二个示例, if (atomic_flag.load() == 0) { /**... **/ atomic_flag = 1;}仍然可以由两个线程输入。 所以new myClass仍然可以多次完成。

只想知道 atomic_flag = 1; 保持 myclass_st 分配线程安全与否。

不。

也许我应该像这样修改代码?

 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; }

如果您打算让多个线程调用get_instance ,那么不会。

我猜你想要:

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