将std :: weak_ptr与std :: shared_ptr一起用于阴影

时间:2017-12-09 20:19:58

标签: c++ c++11 thread-safety shared-ptr weak-ptr

std::weak_ptr on cppreference的文档说明了这个

  

有效地返回expired() ? shared_ptr<T>() : shared_ptr<T>(*this),以原子方式执行。

我的判断和other SO answers确认以下内容不容易发生比赛

int main() {
    auto s_ptr = std::make_shared<T>(...);
    auto w_ptr = std::weak_ptr<T>{s_ptr};

    auto one = std::thread{[&]() {
        auto ptr = w_ptr.lock();
        if (ptr) { ... }
    }};
    s_ptr = std::make_shared<T>(...);

    one.join();
}

然而,这可以可靠地用于程序中的阴影计算吗?通过阴影我的意思是这样的

auto s_ptr = std::make_shared<T>(...);
auto w_ptr = std::weak_ptr<T>{s_ptr};

// thread one
while (...) {
    auto ptr = w_ptr.lock();
    cout << "Value contained is " << *ptr << endl;
}

// thread two
while (...) {
     // do the heavy computation on the side
     auto new_value = fetch_new_value();

     // then "atomically" swap
     s_ptr = std::make_shared<T>(std::move(new_value));
}

这里令人困惑的部分是.lock()返回的内容。可以返回nullptr吗?所有文档都说是操作将以原子方式执行。不说这种互斥意味着什么。指针为空的shared_ptr::operator=中是否存在状态? weak_ptr可以访问此状态吗? shared_ptr::operator= on cppreference的文档似乎没有提到这一点。

2 个答案:

答案 0 :(得分:3)

一旦你的共享指针获得一个新值,你的弱指针就会开始返回nullptr原因是一旦你的共享指针开始指向另一个对象,原始对象就会被破坏。

但是没有未定义的行为交换指针,因为切换是原子的。

(尽管取消引用nullptr返回的w_ptr.lock()值共享指针未定义,可能会导致程序崩溃。

每次使用新值重置共享指针时,都需要获取一个新的弱指针。但是,当你的弱指针lock()被任何人的猜测时,共享指针是否仍指向该新值。

与控制块(引用计数)相关的任何内容都是原子的。因此,获取一个新的弱指针是线程安全的,但不保证指向任何东西(如果其他线程可以访问您的共享指针)。

答案 1 :(得分:1)

此代码可以执行UB:

auto s_ptr = std::make_shared<T>(...);
auto w_ptr = std::weak_ptr<T>{s_ptr};

// thread one
while (...) { // A
  auto ptr = w_ptr.lock(); // B
  cout << "Value contained is " << *ptr << endl; // C
}

// thread two
while (...) {
  // do the heavy computation on the side
  auto new_value = fetch_new_value();

  // then "atomically" swap
  s_ptr = std::make_shared<T>(std::move(new_value)); // X
}

如果第二个线程在执行第一个帖子// X之前执行// B,则weak_ptr不再引用任何数据。

.lock()然后返回&#34; null&#34; shared_ptr,您可以在// C处取消引用。

如果你保护ptr使用它是空的,那么就不会有明显的UB。