Std::Thread join時出現Resource deadlock avoided 問題分析
1.異常現象
當使用std::thread對象的join函數時, C++程序拋出異常
terminate called after throwing an instance of 'std::system_error'
what(): Resource deadlock avoided
可能出現上述問題的情況:
- 持有線程t的對象(std::thread)在t中調用join函數, 也就是自己join自己.
- 兩個或多個線程互相join
2.異常代碼
代碼描述:
- 定義一個全局變量node, node中包含一個線程對象, 此對象在主線程中被賦予一個線程
- 當所有線程結束時釋放全局變量node時, 由於node調用了線程對象的join方法, 拋出上述異常.
#include <iostream>
#include <unistd.h>
#include <thread>
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函數的入口函數在一開始的時候會初始化靜態變量和全局變量(不包括靜態局部變量), 那麼創建的這些變量究竟是存在於主線程(調用入口函數的線程)的棧上, 還是存在於靜態存儲區呢?如果有知道的朋友, 麻煩留言告知.