在破坏调用期间从另一个线程未定义的行为调用对象上的方法?

问题描述 投票:0回答:1

在析构函数调用期间从另一个线程未定义的行为调用对象上的方法(我保证所需的字段仍然存活且可访问并且同步访问它们)?

c++14 draft standard(12.7.4)说:

成员函数,包括虚函数(10.3),可以在构造或销毁期间调用(12.6.2)。当从构造函数或析构函数直接或间接调用虚函数时,包括在构造或销毁类的非静态数据成员期间,以及调用所适用的对象是正在构造的对象(称为x)或者破坏,被调用的函数是构造函数或析构函数类中的最终覆盖,而不是在更派生的类中覆盖它。

试图了解对象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 World\n";
    a_++;
  }

  ~A() {
    std::unique_lock<std::mutex> lock(mt_);
    std::cout << "Destruction started\n";
    lock.unlock();

    thread_.join();
  }

  int a_{0};
  std::mutex mt_;
  std::thread thread_;
};

int main() {
  A a;
  a.reg();
}

PS:我知道我需要同步对字段的访问,并在离开析构函数体后小心停止回调。

PPS:此外,虚拟方法也出现了同样的问题?是否有可能调度虚拟调用以覆盖派生类中的方法(哪些数据已被销毁)?根据上面的引用,它不应该。但是我仍然不确定是否可以将它应用于多线程场景。

c++
1个回答
1
投票

大多数情况下,是的,它是未定义的行为,非常不安全。

一个值得注意的例外是,如果所讨论的方法不需要读取或写入对象的状态(virtual方法计为“需要读取状态”,即使方法本身不读取或写入状态)。如果是这种情况,那么在其上调用方法不会导致未定义的行为。

但它仍然是不安全的,你应该尽可能地尝试防止它发生。

© www.soinside.com 2019 - 2024. All rights reserved.