C++: Std::Thread Join时出现Resource deadlock avoided 问题分析

Std::Thread join时出现Resource deadlock avoided 问题分析

文章目录

  • Std::Thread join时出现Resource deadlock avoided 问题分析
    • 1.异常现象
    • 2.异常代码
    • 3.异常原因分析
    • 4.注意点
    • 5.疑问

1.异常现象

当使用std::thread对象的join函数时, C++程序抛出异常

terminate called after throwing an instance of 'std::system_error'
  what():  Resource deadlock avoided

可能出现上述问题的情况:

  1. 持有线程t的对象(std::thread)在t中调用join函数, 也就是自己join自己.
  2. 两个或多个线程互相join

2.异常代码

代码描述:

  • 定义一个全局变量node, node中包含一个线程对象, 此对象在主线程中被赋予一个线程
  • 当所有线程结束时释放全局变量node时, 由于node调用了线程对象的join方法, 抛出上述异常.

#include 
#include 
#include 
using namespace std;
#define PRINT_THREAD_ID(domain) std::cout << domain << " thread id is:" << std::this_thread::get_id() << std::endl;
class Node
{
public:
  Node(){}
  ~Node(){
    if(proc_thread.joinable())
      proc_thread.join();
  }
  void Start(){
    proc_thread = std::thread(&Node::Proc, this);
  }
private:
  void Proc(){
    for(int i = 0; i < 5; i++){
      sleep(1);
    }
  }
  std::thread proc_thread;
};

Node node;

int main(int argc, char **argv)
{
  std::thread t([](){
    int pid = fork();
    if(pid == 0)
      node.Start();
  });
  if(t.joinable())
    t.join();
  return 0;
}

3.异常原因分析

  • 1.node为全局变量, fork之后被子进程所继承
  • 2.fork之后, 子进程中的主线程开启了Node中的一个工作线程, 但是主线程先退出工作线程变成了主线程.
  • 3.当新的工作线程中的函数执行完之后, 函数栈退出, 由于是最后一个线程, 开始回收内存资源准备退出,同时也退出进程.
  • 4.回收资源时,调用了持有此线程的线程对象的Join方法, 所以抛出了异常what(): Resource deadlock avoided, 也就是自己Join自己引起的异常.

4.注意点

  • 1.如果不开启线程t再fork是不会抛出此异常的, 因为子进程会继承运行main函数的主线程, 而Node则是在此线程上被创建的(存储在静态存储区), 当main退出时, 此线程不会立刻退出, 回退到入口函数, 依次释放栈上的资源,调用join方法.
  • 2.主进程中开启一个线程t, 线程t中fork一个子进程.在线程中fork的目的是使子进程不继承主进程的主线程(运行main函数的线程)
  • 3.子进程继承了主进程中的线程t, 线程t此时为子进程主线程, Node就是存储在静态存储区的资源, 线程t结束之后不会释放此资源, 因为Node不是他的线程栈所创建的.
  • 4.线程中运行的代码段不单单是传入的函数, 也包括创建线程和指定函数运行完毕后的处理代码

5.疑问

众所周知, 静态变量和全局变量都是存储在静态存储区的. 而调用main函数的入口函数在一开始的时候会初始化静态变量和全局变量(不包括静态局部变量), 那么创建的这些变量究竟是存在于主线程(调用入口函数的线程)的栈上, 还是存在于静态存储区呢?如果有知道的朋友, 麻烦留言告知.

你可能感兴趣的:(随笔)