(6)线程的连接和分离

①线程连接
    [1]int pthread_join(pthread_t thread, void **retval);
    pthread_t:  等待的线程尚未退出,那么 pthread_join 的调用线程就会陷入阻塞。
    retval:     接收返回值
        · 等待的线程尚未退出,那么pthread_join 的调用线程就会陷入阻塞。
        · 等待的线程已经退出,那么pthread_join 函数会将线程的退出值(void* 类型存放到retval)指针指向的位置。
        1.pthread_join 函数之所以能够判断是否死锁和连接操作是否被其他线程捷足先登,是因为目标线程的控制结构体 struct pthread 中,存在如下成
            员变量,记录了该线程的连接者。
        2.直接连接自己, 或者A连接B, B又连接A
        
    [2]线程连接(join)与进程等待(wait)的不同点
        1.进程之间的等待只能是父进程等待子进程, 
        2.线程组内的成员是对等的关系,线程组内的任一线程都可其他线程进行连接(join)
        3.进程等待可以等待一个进程组内的所有线程(waipid)
        4.线程的连接操作只能单独连接某个具体的线程: 当库函数尝试连接( join )私自创建的线程时,发现已经被连接过了,就会返回EINVAL 错误。
    
    [3]为什么要连接退出的线程?
        1.已经退出的线程,其空间没有被释放,仍然在进程的地址空间之内。
        2.新创建的线程,没有复用刚才退出的线程的地址空间。
        ==> 造成资源泄漏
        3.当线程组内的其他线程调用pthread_join连接退出线程时,内部会调用__free_tcb函数,该函数会负责释放退出线程的资源。
        4.纵然调用了pthread_join,也并没有立即调用munmap来释放掉退出线程的栈,它们是被后建的线程复用了。(再次反复创建线程,分配线程栈会影响性能)

②线程分离

    [1]设置线程为可分离状态
    int pthread_detach(pthread_t thread);
        thread: 要分离的线程标识ID
        1.如果其他线程并不关心线程的返回值,连接操作就会变成一种负担: 不连接会造成线程资源不释放(泄漏内存)
        2.被设置为分离的线程: 线程退出时,系统自动将线程相关的资源释放掉,无须等待连接。
        3.可以是线程组内其他线程对目标线程进行分离,也可以是线程自己执行 pthread_detach 函数,将自身设置成已分离的状态
            pthread_detach(pthread_self()) // 将本线程设置为可分离状态
        4.如果线程处于已分离的状态,其他线程尝试连接线程时,会返回 EINVAL 错误。
        5.所谓已分离: 是指线程退出后,系统会自动释放线程资源。
    
    [2]创建线程时, 将线程的属性设定为已分离(创建已分离线程) // 线程退出后, 系统自动回收资源
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
        thread_create(&tid, &attr, func,arg);
        // 获取线程分离状态
        int pthread_attr_setdetachstate(pthread_attr_t *attr,int detachstate);
        int pthread_attr_getdetachstate(pthread_attr_t *attr,int *detachstate);    
③.示例代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <pthread.h>
#include <sys/syscall.h> 
#include <sys/prctl.h>

int ret = 123;
void *start_routime1(void *arg)	/* 主线程关心线程退出的返回值 */
{
	printf("start_routime1\n");
	pthread_exit(&ret);// 将返回值的首地址保存在了pret所指向的地方

}
void *start_routime2(void *arg)   /* 主线程不关心线程退出的返回值 */
{
	printf("start_routime2\n");
	pthread_detach(pthread_self());		// 设置为分离状态, 线程退出后自动释放资源
}

/* 这是一个已分离的线程, 线程退出后系统自动释放资源 */
void *start_routime3(void *arg)   /* 主线程不关心线程退出的返回值 */
{
	printf("start_routime3\n");
}

int main(int argc, char **argv)
{
	pthread_t sub_id1, sub_id2, sub_id3;
 	int detachstate;
	pthread_attr_t attr;
	void *pret;
	printf("\n-------------------1--------------------------------\n");
	// 创建的线程1默认为可连接状态
	if(pthread_create(&sub_id1, NULL, start_routime1, NULL))
		perror("pthread_create1 err");
	
	pthread_join(sub_id1, &pret);	
	printf("pret = %d\n", *(int *)pret);	// 必须对该线程进行连接,才能回收该线程的资源
	
	printf("\n-------------------2--------------------------------\n");
	// 创建的线程2默认为可连接状态
	if(pthread_create(&sub_id2, NULL, start_routime2, NULL))
		perror("pthread_create2 err");
	sleep(1);
	
	// 线程2设置了分离状态, 会自动释放资源, 不用进行连接

	// 或者在主线程中将线程2设置为分离状态
	// pthread_detach(sub_id2);
	
	printf("\n------------------3---------------------------------\n");
	// 创建detach线程, 线程退出后, 系统会自动回收资源
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);	// 设置即将创建的线程属性为已分离

	pthread_attr_getdetachstate(&attr, &detachstate);			// 获取线程的分离状态
		if (detachstate == PTHREAD_CREATE_DETACHED)
			printf("pthread 3 PTHREAD_CREATE_DETACHED\n");
		else if (detachstate == PTHREAD_CREATE_JOINABLE)
			printf("pthread 3 PTHREAD_CREATE_JOINABLE\n");
	if(pthread_create(&sub_id3, &attr, start_routime3, NULL));	// 创建线程
		perror("pthread_create3 err");

	memset(&attr, 0, sizeof(attr));
	detachstate = 0;
	
	return 0;
}


/* 执行结果:
book@gui_hua_shu$ gcc -o t join_detach.c -lpthread
book@gui_hua_shu$ ./t
-------------------1--------------------------------
start_routime1
pret = 123

-------------------2--------------------------------
start_routime2

------------------3---------------------------------
pthread 3 PTHREAD_CREATE_DETACHED
pthread_create3 err: Success
*/

猜你喜欢

转载自blog.csdn.net/qq_38813056/article/details/85319361