pthread_exit/pthread_kill之后局部对象之析构
一、多线程与析构函数
这个是在C++编码中可能存在的一个问题,假设说一个线程执行了局部变量的构造函数之后,没有退出局部对象作用域之前,它主动退出线程(pthread_exit)或者被动退出线程(pthread_kill ed),那么这个局部变量的析构函数是否会执行?这个问题对于通常的程序来说影响并不大,但是对于某些依赖在析构函数中执行复杂的系统级对象操作来说是比较重要的(例如释放系统级的信号量,写文件等),并且现在的C库pthread_cleanup_XXX函数实现也依赖于这个特性,所以这里简单单独描述一些。
二、测试代码
[tsecer@Harry pthreadexit]$ ls
main.c Makefile
[tsecer@Harry pthreadexit]$ cat Makefile
default:
g++ main.c -lpthread -o main.exe -lpthread
[tsecer@Harry pthreadexit]$ cat main.c
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
struct dest {
~dest(){printf("in %s\n",__FUNCTION__);}
}
;
void * worker(void * arg)
{
dest mylocal;当线程被pthread_kill的时候,注意这个局部变量的析构函数是否会被执行。
printf("willing sleep \n");
sleep(1000);
printf("after sleep 1000\n");注意这个打印是否能够打印出来。
}
int main()
{
pthread_t thread;
pthread_create(&thread,NULL,worker,NULL);
sleep(2);
printf("killing worker\n");
pthread_cancel(thread);
sleep(2);
}
[tsecer@Harry pthreadexit]$ make
g++ main.c -lpthread -o main.exe -lpthread
[tsecer@Harry pthreadexit]$ ./main.exe
willing sleep
killing worker
in ~dest
[tsecer@Harry pthreadexit]$
三、结果
可以看到,当线程被杀死的时候,它依然顽强的执行了worker函数中局部变量 dest mylocal的析构函数(并且只执行了析构函数,紧邻着sleep之后的print结构并没有打印出来)。
从效果上看,它是保证程序完整性的重要基础,事实上,对于C++代码,这个语言特征的保证也是实现pthread_cleanup_push/pthread_cleanup_pop的C++实现基础。
从编译器实现上看,编译器代码增加了大量的eh_frame内容,其中使用到了DWARFS结构中的CIE及FDE等信息,这些信息是调试器进行堆栈回溯、函数局部变量显示、栈帧寄存器显示的基础。这个结构比较复杂,如果展开可以展开很多内容。我也是大致看了个基本原理,很多东西不能自由展开,这里就不再深入了。
大家知道这个C++语言特征,并且知道它的实现基础是基于DWARFS格式就可以了。事实上,我们从代码中看不到任何cleanup信息,所以如果有同学有时间有兴趣了解它的实现基础的话,可以向这个方向关注一下。