关于使用 shared_ptr 的线程安全问题

Question about the thread-safety of using shared_ptr

众所周知,shared_ptr 仅保证对底层控制块的访问是线程 安全且不保证访问拥有的对象。

那为什么there is a race condition in the code snippet below:

std::shared_ptr<int> g_s = std::make_shared<int>(1);
void f1()
{
    std::shared_ptr<int>l_s1 = g_s; // read g_s
}

void f2()
{
    std::shared_ptr<int> l_s2 = std::make_shared<int>(3);
    std::thread th(f1);
    th.detach();
    g_s = l_s2; // write g_s
}

在上面的代码片段中,确实没有访问名为 g_s 的共享指针的拥有对象。

我现在真的很迷茫。有人可以阐明这个问题吗?

std::shared_ptr<T> 保证对其控制块的访问是 thread-safe,但不能访问 std::shared_ptr<T> 实例本身,它通常是一个具有两个数据成员的对象:原始指针(由 get() 返回的那个)和指向控制块的指针。

在您的代码中,两个线程可能同时访问同一个 std::shared_ptr<int> 实例; f1 读取,f2 写入。

如果两个线程正在访问共享同一对象所有权的两个不同 shared_ptr 实例,则不会存在数据竞争。这两个实例将具有相同的控制块,但对控制块的访问将由库实现适当同步。

如果你需要并发,race-free从多个线程访问一个单个std::shared_ptr<T>实例,你可以使用std::atomic<std::shared_ptr<T>>. (There is also an older interface在 C++20 之前使用,在 C++20 中已弃用。)