0、前言
线程只有两种属性,结合态(joinable)和分离态(detached);
ps:详细示例可以参考该文.
1、pthread_join
1)pthread_join函数的原型
线程默认的属性是结合态。
int pthread_join(pthread_t tid, void ** pthread_return);
2)pthread_join函数特点
- phtread_join函数的第2个参数为void** ,为二重指针,接收的是线程函数中pthread_exit(void* arg);的参数或者是return 的值,可以用来查看pthread_exit传递的参数(如果不关系退出状态,phtread_join的这个参数可以置空,即phtread_join(tid,NULL))。
- pthread_join函数在线程退出时,用来清理线程资源。
- phtread_join函数会阻塞调用方,直至pthread_join所指的线程退出。
-----------------这个特性的优点是,避免出现父线程先于子线程结束的情况,导致子线程还没有结束,主程序退出的情况。
缺点是,阻塞住了主线程,不过我们是多数使用情况下,main()函数在调用pthread_join之后,也不会再调用其他函数,一般只会打印信息之类的了。
因此,默认情况下(在不更改线程属性的情况下)pthread_create需与pthread_join函数同时使用。
3)pthread_join使用示例
void* foo(void*)
{
while(1)
{
sleep(2);
cout<<"thread"<<endl;
}
}
int func()
{
cout<<"main func"<<endl;
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,foo,NULL);
pthread_join(tid,NULL);//会阻塞主线程
func();//该函数等到子线程执行完才执行
return 0;
}
2、pthread_detach
1)pthread_detach函数原型
int pthread_detach(pthread_t tid);
因为线程默认的状态是结合态的,所以,可以通过pthread_detach函数来设置线程为分离态。
2)pthread_detach函数的特点
- 使用pthread_detach函数后,使线程处于分离态;
- 使用pthread_detach函数后,线程在退出后,会自己清理资源
- 相较pthread_join,使用pthread_detach函数不会阻塞主线程,但是无法获取线程的返回值。
- pthread_detach使用时,依然需要配合sleep函数或者while(1);,否则无法保证子线程先于主线程执行完。
3)pthread_detach使用示例
pthead_detach的使用可以有两种形式:
在主线程中直接:pthread_detach(tid);
在线程函数中:pthread_detach(pthread_self());
void* foo(void*)
{
//pthread_detach(pthread_self());//方式2
int i =10;
while(i--)
{
cout<<"thread"<<endl;
}
}
int func()
{
cout<<"main func"<<endl;
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,foo,NULL);
pthread_detach(tid);//方式1//不会阻塞主线程,
sleep(2); //避免主线程先退出
func();//该函数不会等到子线程执行完才执行,会与子线程同时执行
return 0;
}
小结:
1)pthread_join():
创建线程默认的属性就是joinable的,此时需要pthread_create与pthread_join配合使用;
线程创建者通过pthread_join获取线程函数返回值,释放资源等。(jion可以理解为孩子与父母没有分家,有些事还需要父母帮忙完成。)
2)pthread_detach():
使用该函数可以将子线程与主线程分离,子线程结束后,自己回收自己的资源,而不需要主线程回收资源(detach可以理解为孩子与父母分家,事情都需要自己完成)
附录:通过修改线程属性来改变线程的连接、分合状态
除了上述方法外,还可以通过使用设置线程属性来修该线程的状态,以下示例来源于:https://blog.csdn.net/qq_22847457/article/details/89461222
/*DATE: 2019-04-23
*AUTHOR CP
*DESCRIPTION: 设置线程分离属性
*如果在创建线程的时候就知道不需要了解线程的终止状态,那么可以修改pthread_attr_t结构体detachstate属性。
*让线程以分离状态启动。可以使用 pthread_attr_ setdetachstate函数来设置线程的分离状态属性。
*线程的分离属性有
*两种合法值
* PTHREAD_CREATE_DETACHED分离的
* PTHREAD_CREATE_J0INABLE非分离的, 可连接的
* int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
* int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
* 便用 pthread_attr_getdetachstate可以获得线程的分离状态属性
*
* 设置线程分离属性的步骤
* 1.定义线程属性变量 pthread_attr_t attr
* 2.初始化attr, pthread_attr_init(&attr)
* 3.设置线程为分离或非分离 pthread_attr_setdetachstate(&attr,detachstate);
* 所有的系统都会支持线程的分离状态属性,
*/
#include "apue.h"
#include <pthread.h>
void *thread_fun1(void *arg)
{
printf("I'm new thread 1\n");
return (void *)1;
}
void *thread_fun2(void *arg)
{
printf("I'm new thread 2\n");
return (void *)2;
}
int main()
{
pthread_t tid1, tid2;
int err;
pthread_attr_t attr; // 定义属性变量
pthread_attr_init(&attr); // 初始化属性
//pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // 设置属性状态,置为以分离
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); // 设置属性状态,置为可连接
// 创建线程1
err = pthread_create(&tid1, &attr, thread_fun1, NULL);
if (err)
{
printf("create new thread 1 failed\n");
return;
}
// 创建线程1,默认属性
err = pthread_create(&tid2, NULL, thread_fun2, NULL);
if (err)
{
printf("create new thread 2 failed\n");
return;
}
// 连接线程1
err = pthread_join(tid1, NULL);
if (!err)
{
printf("join thread 1 success\n");
}
else
{
printf("join thread 1 failed\n");
}
// 连接线程2
err = pthread_join(tid2, NULL);
if (!err)
{
printf("join thread 2 success\n");
}
else
{
printf("join thread 2 failed\n");
}
// 销毁属性变量
pthread_attr_destroy(&attr);
return 0;
}