在销毁期间从另一个线程调用对象上调用方法是否未定义行为?
Is calling a method on an object during destruction call from another thread undefined behaviour?
在析构函数调用期间从另一个线程调用对象上的方法是否未定义行为(我保证必填字段仍然有效且可访问并且对它们的访问是同步的(?
C ++ 14草案标准(12.7.4(说:
成员函数,包括虚函数 (10.3(,可以调用 在施工或销毁期间(12.6.2(。当虚拟函数 直接或间接从构造函数或从 析构函数,包括在建造或销毁期间 类的非静态数据成员,以及调用的对象 应用是正在建造或破坏的对象(称为X(, 调用的函数是构造函数 or 中的最终覆盖器 析构函数的类,而不是在派生更多的类中重写它的类。
尝试了解对象 A 拥有线程 B 和线程 B 的模式是否有效,可以随时调用对象 A 的回调。对象 A 的析构函数将在销毁任何相关状态之前加入线程。
相关代码示例:
#include <vector>
#include <thread>
#include <atomic>
#include <iostream>
struct A {
void reg() {
thread_ = std::thread([this]() {
while (a_ < 10) {
pr();
}
});
}
void pr() {
std::unique_lock<std::mutex> lock(mt_);
std::cout << "Hello Worldn";
a_++;
}
~A() {
std::unique_lock<std::mutex> lock(mt_);
std::cout << "Destruction startedn";
lock.unlock();
thread_.join();
}
int a_{0};
std::mutex mt_;
std::thread thread_;
};
int main() {
A a;
a.reg();
}
PS:我知道我需要同步对字段的访问,并注意在离开析构函数正文后停止回调。
PPS:另外,虚拟方法也存在同样的问题?是否可以将虚拟调用调度到派生类中的重写方法(数据已被销毁(?根据上面的引用,它不应该。但我仍然不确定我们是否可以将其应用于多线程场景。
大多数时候,是的,这是未定义的行为,非常不安全。
一个值得注意的例外是,如果相关方法不需要读取或写入对象的状态(virtual
方法算作"需要读取状态",即使方法本身不读取或写入状态(。如果是这种情况,则对其调用该方法不会导致未定义的行为。
不过,它仍然是不安全的,您应该尽可能多地防止它发生。
相关文章:
- 返回指向对象的指针的函数调用是否为 prvalue?
- MFC 中的窗口消息管理:添加基类调用是否是强制性的?
- 在 v8 JavaScript 中重复调用C++是否有巨大的开销?
- dynamic_cast每次调用是否比具有空检查的缓存变量更昂贵?
- 对外部函数的调用是否强制从内存加载
- clang 拒绝具有尾随 decltype 返回类型的模板调用是否正确,具体取决于其重载之一?
- 构造函数的初始值设定项列表中的函数调用是否按顺序排序?
- 从 std::d eque 线程对 emplace_back() 和运算符 []() 的并发调用是否安全?
- 函数调用是否作为另一个函数参数遵循任何定义的行为
- 汇编函数调用是否会导致所有寄存器被推送到堆栈中
- 来自另一个线程的 SendMessage() 调用是否将消息发布到消息队列
- Inotify和Select调用是否可以合并
- 函数调用是否需要表达式
- 对 std 构造函数的调用是否需要限定
- 此构造函数调用是否具有特殊名称
- 将 delete 作为运算符或函数调用是否有任何区别
- 使用 COM 跨 CRT 边界调用是否安全
- 是否有一种方法可以使用SFINAE来确定对模板化函数的调用是否会由于所提供的类型而失败
- 类方法调用是否会在for循环中进行优化
- 对运算符的调用是否'delete'同步的?