当调用std :: thread.detach时出乎意料的行为

Unexpected behavior when std::thread.detach is called

本文关键字:出乎意料 detach 调用 std thread      更新时间:2023-10-16

我一直在尝试更好地了解C 线程,通过它,我写了以下示例:

#include <functional>
#include <iostream>
#include <thread>
class Test {
 public:
  Test() { x = 5; }
  void act() {
    std::cout << "1" << std::endl;
    std::thread worker(&Test::changex, this);
    worker.detach();
    std::cout << "2" << std::endl;
  }
 private:
  void changex() {
    std::cout << "3" << std::endl;
    x = 10;
    std::cout << "4" << std::endl;
  }
  int x;
};
int main() {
  Test t;
  t.act();
  return 0;
}

对我来说,与g++链接的CC_1汇编时,我应该得到以下输出:

1
2
3
4

由于cout呼叫按该顺序。但是,输出不一致。1和2总是按顺序打印,但有时省略了3和或4。即。12123123412344

我的工作理论是,在工作人员线程开始工作或完成之前,主线程将退出,从而导致输出的省略。我可以立即想到解决此问题的解决方案,以创建一个全局布尔变量,以表示工作线程完成何时完成之前的状态更改,然后才能退出。这减轻了这个问题。

然而,在我看来,这就像一种可能具有更干净的解决方案的方法,尤其是对于这种问题经常出现的问题。

只是一些一般建议,这些建议既适用于在C 中使用RAW PTHREADS以及在STD :: Thread中包裹的Pthreads:获得可读性,可理解和可疑行为的最佳方法是使线程使线程同步和终生管理明确。IE。避免使用pthread_kill,pthread_cancel,在大多数情况下,避免脱离线程,而是明确加入。

我喜欢的一种设计模式是使用STD原子标志。当主线程想要退出时,它将原子标志设置为true。工人线程通常会在循环中进行工作,并经常合理地检查原子旗。每圈循环一次一次。当他们发现Main命令他们退出时,他们会清理并返回。然后主线程与所有工人一起加入:s。

有一些特殊情况需要额外的注意,例如,当一个工人陷入阻止SYSCALL和/或C库功能时。通常,该平台提供了摆脱此类阻止呼叫的方法,而无需求助于例如PTHREAD_CANCEL,因为线程取消与C 的工作非常差。如何避免阻塞的一个示例是getAddrinfo_a的Linux manpage,即异步网络地址转换。

另一种不错的设计模式是工人在例如选择()。然后,您可以在Main和Worker之间添加额外的控制管。主要信号通过send():在管道上的一个字节上辞职,如果工人在select()中醒来,请醒来。

如何完成此操作的示例:

#include <functional>
#include <iostream>
#include <thread>
class Test {
    std::thread worker; // worker is now a member
 public:
  Test() { x = 5; } // worker deliberately left without a function to run.
  ~Test()
  {
    if (worker.joinable()) // worker can be joined (act was called successfully)
    {
        worker.join(); // wait for worker thread to exit.
                       // Note destructor cannot complete if thread cannot be exited. 
                       // Some extra brains needed here for production code.
    }
  }
  void act() {
    std::cout << "1" << std::endl;
    worker = std::thread(&Test::changex, this); // give worker some work
    std::cout << "2" << std::endl;
  }
 // rest unchanged.
 private:
  void changex() {
    std::cout << "3" << std::endl;
    x = 10;
    std::cout << "4" << std::endl;
  }
  int x;
};
int main() {
  Test t;
  t.act();
  return 0;
} // test destroyed here. Destruction halts and waits for thread.