我对并发世界还不是很了解,但从我所读的内容来看,我理解下面的程序在执行时是未定义的。如果我理解正确,这个程序不是线程安全的,因为我同时以非原子方式并发读写shared_ptr和计数器变量。
#include <string>
#include <memory>
#include <thread>
#include <chrono>
#include <iostream>
struct Inner {
Inner() {
t_ = std::thread([this]() {
counter_ = 0;
running_ = true;
while (running_) {
counter_++;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
});
}
~Inner() {
running_ = false;
if (t_.joinable()) {
t_.join();
}
}
std::uint64_t counter_;
std::thread t_;
bool running_;
};
struct Middle {
Middle() {
data_.reset(new Inner);
t_ = std::thread([this]() {
running_ = true;
while (running_) {
data_.reset(new Inner());
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
});
}
~Middle() {
running_ = false;
if (t_.joinable()) {
t_.join();
}
}
std::uint64_t inner_data() {
return data_->counter_;
}
std::shared_ptr<Inner> data_;
std::thread t_;
bool running_;
};
struct Outer {
std::uint64_t data() {
return middle_.inner_data();
}
Middle middle_;
};
int main() {
Outer o;
while (true) {
std::cout << "Data: " << o.data() << std::endl;
}
return 0;
}
我的疑惑来自以下内容:
Middle::inner_data
中的data_->counter
的访问是否安全?- 如果线程 A 有一个成员
shared_ptr<T> sp
,并决定在线程 B 执行shared_ptr<T> sp = A::sp
时对其进行更新,那么复制和销毁是否是线程安全的?或者我会因为对象正在被销毁而导致复制失败。
在什么情况下(我可以用某些工具检查此项?)未定义的行为很可能是指 std::terminate
? 我怀疑类似上面的问题发生在我的一些生产代码中,但我不能确定,因为我对1和2感到困惑,但自从我写了这个小程序以来,它已经运行了几天,什么也没有发生。
代码可以在此处检查:https://godbolt.org/g/saHz94
std::terminate
?不是的,这意味着程序可以做任何它想做的事情。这包括std::terminate
、给出错误结果、无限循环或其他各种效果。这些效果可能会因编译器版本、标志、代码更改甚至编译而发生变化。对于这段代码没有任何推理。 - nwp