应用场景:
服务器,创建了多个服务子线程,而后主线程“无所事事”,进程会被关闭,导致子线程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; } } }
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_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。