应用场景:
服务器,创建了多个服务子线程,而后主线程“无所事事”,进程会被关闭,导致子线程sleepA和sleepB无法正常执行完成。(假设sleepA()和sleepB()都是沉睡若干秒的函数,这个肯定要比程序执行到main结束那几步所花费时间要长)
int main()
{
int iRet = 0;
iRet = pthread_create(&thread_a_id,NULL,sleepA,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
iRet = pthread_create(&thread_b_id,NULL,sleepB,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
}
想让sleepA和sleepB能够正常持续运行下去,进程必须赖下去——让主线程不停止。低劣的做法如下:
int main()
{
int iRet = 0;
iRet = pthread_create(&thread_a_id,NULL,sleepA,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
iRet = pthread_create(&thread_b_id,NULL,sleepB,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
while(1)
{
sleep(60);
}
}
提倡的做法如下:
int main()
{
int iRet = 0;
iRet = pthread_create(&thread_a_id,NULL,sleepA,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
iRet = pthread_create(&thread_b_id,NULL,sleepB,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
pthread_join(thread_a_id,NULL);
pthread_join(thread_b_id,NULL);
}
这里注意,默认情况新建线程是joinable的,可以用join,如果设置成别的,也会join不成。
============================================================================
另外,这个join之后不一定就主进程结束,这样用就太单纯了。
应用一:
比如本来要持续运行服务的子线程,可以pthread_join()之后再pthread_create(),这样就能起到内部容错和保活的作用。
int main()
{
int iRet = 0;
iRet = pthread_create(&thread_a_id,NULL,sleepA,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
printf("before join a\n");
pthread_join(thread_a_id,NULL);
printf("after join a\n");
iRet = pthread_create(&thread_a1_id,NULL,sleepA,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
}
但这只是想象,实际上并不能成功,问题在哪呢?
# ./a.out
before join a
sleepA called!
now sleepA over!
after join a
可以看到,程序不可能在join之后直接终结,后续流程还是要走,但是却并没有第二次运行sleepA(),如果只是第二次pthread_create失败,也并没有打印失败。
关于id值,使用和之前相同的thread_a_id或者单独的一个thread_a1_id结果都是一样的不成功!
关于函数,使用sleepA或者sleepB都一样的不成功,所以也和函数没关系!
所以,pthread_join()之后到底算个什么状态?为什么ptread_create不行了?
其实,上边是我故意做的错误示范,第二次pthread_create()之后主线程结束了啊,缺少第二个join来阻塞住进程啊!!!!!!后根一个该id对应的join操作,解决!
# ./a.out
before join a
sleepA called!
now sleepA over!
after join a
now sleepB over!
============================================================
应用二:
int main()
{
int iRet = 0;
while(1)
{
iRet = pthread_create(&thread_a_id,NULL,sleepA,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
printf("before join a\n");
pthread_join(thread_a_id,NULL);
printf("after join a\n");
}
}
运行结果如下,不强制关闭不会停。
# ./a.out
before join a
sleepA called!
now sleepA over!
after join a
before join a
sleepA called!
now sleepA over!
after join a
before join a
sleepA called!
now sleepA over!
after join a
before join a
sleepA called!
now sleepA over!
after join a
before join a
sleepA called!
^C
应用三:
这个线程的处理还可以这样用,在一个大循环内,等待信号,有一个请求到来就新建一个线程单独去处理这个请求,然后结束再回来。(这里假设a是信号量,是一个全局变量,有一个单独的线程传信号——改a的值,通过信号量a来触发服务sleepA)
#include <stdio.h>
#include <pthread.h>
static pthread_t thread_a_id;
static pthread_t thread_a1_id;
static pthread_t thread_b_id;
static int i = 0;
static int a = 0;
void* sleepA(void *p)
{
printf("sleepA called!\n");
sleep(1);
printf("now sleepA over!\n");
return NULL;
}
void* setA(void *p)
{
while(1)
{
sleep(2);
a = 1;
}
return NULL;
}
int main()
{
int iRet = 0;
iRet = pthread_create(&thread_b_id,NULL,setA,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
while(1)
{
if(a == 1)
{
iRet = pthread_create(&thread_a_id,NULL,sleepA,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
printf("before join a\n");
pthread_join(thread_a_id,NULL);
printf("after join a\n");
a = 0;
}
}
}
如上,两秒一置1,sleepA只睡1秒,还忙得过来,假如1秒一置1,sleepA睡2秒呢?睡5秒呢?代码变动如下
void* sleepA(void *p)
{
printf("sleepA called!\n");
sleep(5);
printf("now sleepA over!\n");
return NULL;
}
void* setA(void *p)
{
while(1)
{
sleep(1);
a = 1;
}
return NULL;
}
明显会慢得多!!!因为pthread_join()是阻塞的,这样一次只可能有一个线程去处理请求,不能达到想要的效果。
应用四:
这时候就不能用pthread_join()了,要用pthread_detach(),这个非阻塞,等于生完孩子就不管了,放养,最后也能回收线程资源(这些join和detach什么的,主要就是等着回收资源)。
#include <stdio.h>
#include <pthread.h>
static pthread_t thread_a_id;
static pthread_t thread_a1_id;
static pthread_t thread_b_id;
static int i = 0;
static int a = 0;
void* sleepA(void *p)
{
printf("sleepA called!\n");
sleep(5);
printf("now sleepA over!\n");
return NULL;
}
void* setA(void *p)
{
while(1)
{
sleep(1);
a = 1;
}
return NULL;
}
int main()
{
int iRet = 0;
iRet = pthread_create(&thread_b_id,NULL,setA,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
while(1)
{
if(a == 1)
{
iRet = pthread_create(&thread_a_id,NULL,sleepA,NULL);
if(iRet != 0)
{
printf("create failed!\n");
}
printf("before detach a\n");
pthread_detach(thread_a_id);
printf("after detach a\n");
a = 0;
}
}
}
pthread_detach(),这个在子线程(pthread_self())中和父线程(child_thread_id)中用法略有不同,但本质一样,参数都是要detach的那个线程的id。