std::weak_ptr 和相应的 std::shared_ptr 之间是否存在数据竞争?

Is there any data race between std::weak_ptr and corresponding std::shared_ptr?

根据 cppref,跨多个线程访问 shared_ptrconst 成员是安全的。但是,当我们有一个 weak_ptr 对应于一个 shared_ptr 时,这个说法有效吗?

例如假设以下代码:

#include <memory>
#include <iostream>
#include <thread>

std::shared_ptr<int> sp;
std::weak_ptr<int> gw;

int main()
{
    sp = std::make_shared<int>(42);
    gw = sp;
    auto th1 = std::thread([]{
        for (int i = 0; i < 200; i++) {
            if (sp.use_count() > 1) {
                std::cout << i << "\n";
                std::this_thread::yield();
            }
        }
    });
    auto th2 = std::thread([]{
        for (int i = 0; i < 20; i++) {
            if (auto l = gw.lock()) {
                std::cout << "locked ->" << l.use_count() << "\n";
                std::this_thread::yield();
            }
        }
    });
    th1.join();
    th2.join();
}

这段代码创建了 2 个线程。一个检查 shared_ptr()use_count(),这是一种 const 方法,另一个使用 lock() 锁定 weak_ptr(),这也是一种 const 方法.但实际上,当我在 weak_ptr 上调用 lock 时,我实际上增加了 shared_ptr 的引用计数,这不是线程安全的,除非引用计数在内部受到保护。我想知道在这种情况下我是否会进行数据竞赛。按照标准,这应该是线程安全的吗?

是的。引用计数器是原子的,因此您的示例中没有数据竞争。

也就是说,对 std::shared_ptr 指向的对象的可变操作不是原子操作,因此必须像保护通过普通指针访问一样保护它们。