如果在多线程中重置相同的shared_ptr,不会崩溃

问题描述

我只想确认在多线程中锁定并重置为同一智能指针是否安全?如果没有lock_guard,那不是安全的,因为它不是线程安全的方法?我认为reset不是线程安全的,但是,如果我删除了锁,则不会观察到崩溃。

class foo {
public:
   foo()
   {
       std::cout << "foo constructed" << std::endl;
   }
   ~foo()
   {
       std::cout << "foo destructed" << std::endl;
   }
};
int main(int argc,const char * argv[]) {
    std::shared_ptr<foo> f = std::make_shared<foo>();
    conqueue = dispatch_queue_create("MyConcurrentDiapatchQueue",disPATCH_QUEUE_CONCURRENT);
    static std::mutex io_mutex;
    for (int i = 0; i < 100000; i++)
    {
        dispatch_async(conqueue,^{

            std::lock_guard<std::mutex> lk(io_mutex); // no crash without this line as well
            f.reset(); // it's safe? No crash if I reset the same shared_ptr in multi-threads.
        });
    }
    return 0;
}

解决方法

shared_ptr对象不是线程安全的,指向的对象也不是线程安全的。只有引用计数是线程安全的。所以是的,您需要使用防护装置。

在C ++ 20中,有std::atomic<std::shared_ptr<T>>

,

文档不保证该组件的安全性。本质上,如果标准对此无能为力,那么您的假设是正确的。您必须拥有那个锁四方或提供相同功能的任何东西。

崩溃可能是不可观察的,因为直到尝试在并发线程中读取指针,您才真正处于竞争状态,因为您实际上并没有尝试使用该值(复位所做的只是更改指针值)。

好吧,您不能依靠自己看不到UB,UB是薛定inger的猫。