Linux线程的连接和分离

我们知道,对多进程的程序而言。如果子进程结束后父进程还未结束,那么该子进程将会处于僵尸状态,我们称之为“僵进程”。对于僵进程,直到父进程调用wait()或waitpid()函数后,僵进程的状态才会被解除,此时子进程的资源才得以释放。

1.僵线程

对线程而言,同样有类似于“僵线程”的概念。比如,主线程(或任何其他一个线程)没有对即将结束的子线程调用pthread_join()函数,当该线程结束之后就会处于僵线程状态。

僵线程状态下的线程同样面临着一个问题:线程已经结束,但是线程特有的资源(如线程ID,栈空间等)却没有释放。

2.线程连接(join

僵线程的资源得不到及时的释放,势必会影响系统资源的分配效率。通过线程连接(pthread_join()函数)可以避免僵线程(主线程会等待从线程结束,并回收从线程的资源),pthread_join()函数原型如下:

其中,参数thread指明被连接的线程对象;retval用来接收被连接线程结束时的返回值,若不关注可以置为NULL。

但是,解决了僵线程之后,问题又来了:当主线程A调用pthread_join()函数连接从线程B之后,在B没有运行结束之前A线程会一直阻塞。有如下示例:

编译、运行:

主线程A会一直阻塞,如果A在pthread_join()之后还有其他业务需要处理的话(比如监听连接等等),这就是一种有缺陷的设计。

3.线程分离(detach

虽然pthread_join()解决了僵线程的问题,但同时也带来了主线程阻塞的附加问题。那么,有没有一种既不会让从线程沦为僵线程,也不会让主线程阻塞的方案呢?

将线程设置为分离状态,可以在避免僵线程的同时不会阻塞主线程。设置线程分离有两种方法:一种是在创建线程时设置线程属性为分离的;另一种是调用pthread_detach()函数完成线程分离属性的设置(具体接口可参考man手册)。

有如下示例:

编译、运行:

此时,B线程在运行结束之后会自动释放资源,A线程也不会阻塞。但同时也会带来另一个问题:上述示例中,我有意的将A线程休眠了1毫秒,如果将usleep(1000)注释掉的话,主线程A执行完后会直接退出,分离状态的B线程将不会运行:

这是因为在main()函数内的主线程一旦退出,进程就退出了,其他线程也会随之结束。所以,对于存在分离状态的程序设计,你必须通过某种手段使主线程一直运行直到其他线程运行结束。当然,你也可以在main()函数内调用pthread_exit()函数,这会使得进程在所有线程运行结束之后才会退出。

4.其他

任何一种特性的实现都是为了解决某一特定问题,但同时往往会带来一定的附加问题。所以,不管线程的状态是joined还是detached,在充分了解其内部原理之后,做到尽可能的扬长避短就够了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注