【发布时间】:2020-12-15 22:54:14
【问题描述】:
在这个程序中,为什么第 14 行的析构函数会为同一个 mystruct_t 实例调用两次?
我假设这个程序中的所有指针操作都是线程安全的。我认为原子更新不适用于我的系统或编译器。 我在 MSVC 2017、MSVC 2019 和 clang 上试过这个
/* This crashes for me (line 19) */
#include <iostream>
#include <vector>
#include <thread>
#include <memory>
#include <chrono>
#include <assert.h>
struct mystruct_t {
int32_t nInvocation = 0;
~mystruct_t();
mystruct_t() = default;
};
mystruct_t::~mystruct_t() {
nInvocation++;
int nInvoke = nInvocation;
if (nInvoke > 1) {
/* destructor was invoked twice */
assert(0);
}
/* sleep is not necessary for crash */
//std::this_thread::sleep_for(std::chrono::microseconds(525));
}
std::shared_ptr<mystruct_t> globalPtr;
void thread1() {
for (;;) {
std::this_thread::sleep_for(std::chrono::microseconds(1000));
std::shared_ptr<mystruct_t> ptrNewInstance = std::make_shared<mystruct_t>();
globalPtr = ptrNewInstance;
}
}
void thread2() {
for (;;) {
std::shared_ptr<mystruct_t> pointerCopy = globalPtr;
}
}
int main()
{
std::thread t1;
t1 = std::thread([]() {
thread1();
});
std::thread t2;
t2 = std::thread([]() {
thread2();
});
for (int i = 0;; ++i) {
std::this_thread::sleep_for(std::chrono::microseconds(1000));
std::shared_ptr<mystruct_t> pointerCopy = globalPtr;
globalPtr = nullptr;
}
return 0;
}
【问题讨论】:
-
您的代码有未定义的行为。您对
globalPtr的修改和读取没有同步。 -
你的同步/线程安全在哪里?
-
这里为什么需要同步访问?
-
因为标准是这么说的。
-
std::shared_ptr的内部控制块是线程安全的。std::shared_ptr本身对于读写访问不是线程安全的。
标签: c++ multithreading thread-safety shared-ptr