c++ - 调用 std::thread.detach 时的意外行为

标签 c++ linux

我一直在努力加深对 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;
}

对我来说,当使用 -pthread 链接的 g++ 编译时,我应该得到以下输出:

1
2
3
4

因为 cout 调用的顺序是这样的。但是,输出不一致。 1 和 2 总是按顺序打印,但有时 3 和或 4 会被省略或重复打印。 12123123412344

我的工作原理是主线程在工作线程开始工作或完成之前退出,从而导致输出遗漏。我可以立即想到解决这个问题的方法,创建一个全局 bool 变量来表示工作线程何时完成,主线程在退出前等待状态更改。这缓解了这个问题。

但是,对我来说,这感觉像是一种非常困惑的方法,可能有一个更干净的解决方案,尤其是对于线程中可能经常出现的此类问题。

最佳答案

只是一些一般性建议,适用于在 C++ 中使用原始 pthread 和包装在 std::thread 中的 pthread:获得可读、可理解和可调试行为的最佳方法是使线程同步和生命周期管理明确。 IE。避免使用 pthread_kill、pthread_cancel,并且在大多数情况下,避免分离线程,而是进行显式连接。

我喜欢的一种设计模式是使用标准原子标记。当主线程想要退出时,它将原子标志设置为 true。工作线程通常在一个循环中完成它们的工作,并经常检查原子标志,例如每圈循环一次。当他们发现 main 命令他们退出时,他们清理并返回。主线程然后加入:s 与所有 worker 。

有一些特殊情况需要格外小心,例如,当一名工作人员卡在阻塞的系统调用和/或 C 库函数中时。通常,该平台提供了摆脱此类阻塞调用的方法,而无需求助于例如pthread_cancel,因为线程取消在 C++ 中的效果非常差。如何避免阻塞的一个示例是 getaddrinfo_a 的 Linux 联机帮助页,即异步网络地址转换。

另一个不错的设计模式是当员工 sleep 时,例如选择()。然后,您可以在 main 和 worker 之间添加一个额外的控制管道。 Main 通过 send() 向 worker 发出退出信号:在管道上发送一个字节,从而在 select() 中休眠时唤醒 worker。

关于c++ - 调用 std::thread.detach 时的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54952410/

相关文章:

c++ - 为什么在函数内部使用静态变量会使它运行得更慢?

c++ - 出错时cin做什么

c++ - 如何将命令行参数与 C++ 中的选项一起传递给函数?

c++ - boost 字符串拆分以消除单词中的空格

c++ - Boost ASIO - 什么是异步

linux - 在 BASHRC 与命令行中启动后台进程之间的区别

Linux文件权限和Java问题(权限保留)

linux - 必须在 macbook 上运行导出命令才能使用 PhoneGap 创建 Android 项目

linux - 如何在 x86 汇编中调用 fgets?

linux - 如何为 php 文件安排 cronjob?