C/C++中分离(detach)线程的陷阱
版权声明
本文为博主原创文章,未经博主允许不得转载。
线程资源回收
线程资源的回收有两种方式:
- 连接线程 —— int pthread_join(pthread_t thread, void **retval);
- 分离线程 —— int pthread_detach(pthread_t thread);
pthread_join()
- 调用pthread_join()会使得当前线程阻塞等待
- 当目标线程退出函数会立即返回,然后线程资源回收
- 目标函数必须是joinable的(线程创建后默认就是joinable)
- 如果retval不是空指针,那么会在retval返回目标线程退出状态
- 如果当前线程在等待过程被杀死,那么目标线程还是继续joinable
- 请勿多个线程同时join一个目标线程
pthread_detach()
- pthread_detach将一条线程由joinable转换成detached
- 分离线程的好处是线程退出后,省略了join的步骤,自己回收资源
- 已经处于detached的线程切勿再次detached
什么时候分离线程会存在陷阱?
- 一个分离线程使用一个共享资源
- 分离线程的生命周期比所使用的资源的生命周期长
那么就有可能造成未知的错误。
例如:
子线程使用一个全局对象(object),子线程与程序一并退出。
由于程序退出的顺序是:
- 对象析构
- 子线程退出
- 主线程退出
因此,程序退出过程中,全局对象会调用自己的析构函数,此时,对象生命周期结束,对象被销毁。但是,子线程还没马上死亡,子线程仍然有可能继续调用已经析构的对象。期望的结果是安全退出程序,结果却造成了未知的错误。
方法论
- 不要使用分离线程
- 分离线程不要使用共享资源
- 主线程退出前主动销毁子线程(主线程是主动的)
- 使用条件变量,主线程等待子线程退出(主线程是被动的)
- 使用
void quick_exit (int status)
函数,直接退出,不调用析构函数
既使用quick_exit(),又需要析构
使用 int at_quick_exit( void (*func)(void) )
函数,注册退出函数。
PS
quick_exit()
系列函数包含在<stdlib.h>
中,但Windows不一定(具体和编译器、编译器版本都有关)。