这种创建带有指向实例的指针的分离 std::thread 的方式是错误的吗?

Is this way of creating detached std::thread with pointer to instance wrong?

本文关键字:thread 方式 std 错误 分离 指针 创建 实例      更新时间:2023-10-16

我遇到过一些类,它们的唯一功能是在循环中连续执行一些工作,它们的设计使得它们定义了一个公共方法,可以调用该方法以在新std::thread中调用此成员函数。我指的是这样的东西:

class ThreadLooper {
 public:
  ThreadLooper(const std::string &thread_name)
      : thread_name_{thread_name}, loopCounter_{0} {}
  ~ThreadLooper() {
    cout << thread_name_ << ": destroyed and counter is " << loopCounter_
         << std::endl;
  }
  void run() {
    std::thread([this]() { detachedThreadLoop(); }).detach();
  }
 private:
  void detachedThreadLoop() {
    cout << thread_name_ << ": detachedThreadLoop() started running"
         << std::endl;
    while (true) {
      using namespace std::literals::chrono_literals;
      std::this_thread::sleep_for(2s);
      ++loopCounter_;
      cout << thread_name_ << ": counter is " << loopCounter_ << std::endl;
    }
  }
  std::string thread_name_;
  std::atomic_uint64_t loopCounter_;
};
int main() {
  cout << "In main()" << std::endl;
  {
    ThreadLooper threadLooper{"looper1"};
    threadLooper.run();
    using namespace std::literals::chrono_literals;
    std::this_thread::sleep_for(20s);
    cout << "main() done sleeping, exiting block scope..." << std::endl;
  }
  while (true) {
    using namespace std::literals::chrono_literals;
    std::this_thread::sleep_for(20s);
    cout << "main() woke up..." << std::endl;
  }
  return 0;
}

似乎因为在分离的线程中运行的函数具有指向实例的指针,但可以在该实例的生存期之后继续运行,这很糟糕。我见过其他类,其中线程没有分离,然后在析构函数中设置了一个标志来告诉线程循环退出,然后将线程加入析构函数中。似乎后者是执行此操作的正确方法,并且前者依赖于这样一个事实,即该类仅在其实例在程序持续时间内存在的情况下使用。这是正确的还是我错过了什么?

是的,使用 std::thread::detach 意味着您需要有自己的方法来确保线程在销毁它使用的所有资源之前终止。

在这种情况下,当程序退出main()中的第一个块范围时,ThreadLooper将调用未定义的行为。最好不要使用 detach()然后std::thread如果你忘记在线程(及其包含对象)被销毁之前调用join(),它将调用std::terminate