pthread_join与pthread_detach
前言
一、线程不join的结果
在主线程退出时,会调用exit导致线程退出,所有的子线程都会被停止执行。不管这个线程当前的属性是joinable还是detached。
二、等待子线程执行完毕的几种情况
1.阻塞主线程
#include "stdio.h"
#include "pthread.h"
#include "unistd.h"
#include "string.h"
#include "stdlib.h"
#define MAX_STRING_NUM 15
#define PUT_TO_STDOUT(a) write(fileno(stdout),a, strlen(a))
void *echo2terminal(void *data){
//pthread_detach(pthread_self());
sleep(3);
char dest[1024];
strcpy(dest, "this is echo:");
strcat(dest, data);
strcat(dest, "\n");
write(fileno(stdout), dest, strlen(dest));
return NULL;
}
int main(){
pthread_t t;
char *strings[MAX_STRING_NUM] = {
"cccc", "java", "c++", "python", "JS",
"1cccc", "1java", "1c++", "1python", "1JS",
"2cccc", "2java", "2c++", "2python", "2JS",
};
for(int i=0;i<MAX_STRING_NUM;i++){
PUT_TO_STDOUT(strings[i]);
if(pthread_create(&t, NULL, echo2terminal, (void *)strings[i])){
exit(1);
}
PUT_TO_STDOUT("ok\n");// write是系统调用,所以不用行缓冲直接出来
}
while (1){}
return 0;
在这个程序里,如果不加入其中的while死循环,主进程就会可能在子进程结束前结束(子线程的函数sleep了3s),导致子线程中的内容无法打印。但是这种办法有个坏处,它无法释放子线程占有的某些资源(类似子进程退出时也无法自行释放其某些属性),所以要用join在主线程进行回收。
2.使用pthread_join
代码如下(示例):
#include "stdio.h"
#include "pthread.h"
#include "unistd.h"
#include "string.h"
#include "stdlib.h"
#define MAX_STRING_NUM 15
#define PUT_TO_STDOUT(a) write(fileno(stdout),a, strlen(a))
void *echo2terminal(void *data){
//pthread_detach(pthread_self());
sleep(3);
char dest[1024];
strcpy(dest, "this is echo:");
strcat(dest, data);
strcat(dest, "\n");
write(fileno(stdout), dest, strlen(dest));
return NULL;
}
int main(){
pthread_t t[15];
char *strings[MAX_STRING_NUM] = {
"cccc", "java", "c++", "python", "JS",
"1cccc", "1java", "1c++", "1python", "1JS",
"2cccc", "2java", "2c++", "2python", "2JS",
};
for(int i=0;i<MAX_STRING_NUM;i++){
PUT_TO_STDOUT(strings[i]);
if(pthread_create(&t[i], NULL, echo2terminal, (void *)strings[i])){
exit(1);
}
PUT_TO_STDOUT("ok\n");// write是系统调用,所以不用行缓冲直接出来
}
for (int i = 0; i < MAX_STRING_NUM; ++i) {
pthread_join(t[i], NULL);
}
return 0;
}
这样可以在主线程中等待子线程执行完毕,并把资源回收。
3.pthread_detach的作用
如果我们在监听一个listen套接字时,为每一个已连接套接字创建一个子线程,由于join是阻塞的,我们不可能调用join对其进行资源回收,此时要用到pthread_detach让子线程在执行完毕时自行回收资源。
如《UNIX网络编程卷一》541页,我们不可能在箭头处进行join。
我们用获取用户输入来模拟监听套接字。
#include "stdio.h"
#include "pthread.h"
#include "unistd.h"
#include "string.h"
#include "stdlib.h"
#define MAX_INPUT_NUM 100
#define PUT_TO_STDOUT(a) write(fileno(stdout),a, strlen(a))
void *echo2terminal(void *data){
pthread_detach(pthread_self());
sleep(3);
char dest[1024];
strcpy(dest, "this is echo:");
strcat(dest, data);
write(fileno(stdout), dest, strlen(dest));
free(data);
return NULL;
}
int main(){
pthread_t t;
for(;;){
char * input = (char *)malloc(MAX_INPUT_NUM);
read(fileno(stdin), input, MAX_INPUT_NUM);
if(pthread_create(&t, NULL, echo2terminal, (void *)input)){
exit(1);
}
}
return 0;
}
write和printf
在测试以上代码时,出现了先执行printf后执行write但printf打印的内容却在write后边的情况。
这是因为printf是c语言的函数,它在输出时具有行缓冲,如果printf的内容没有换行符的时候是不会输出到命令行的,但是write是系统调用,会直接打印到命令行。
总结
- 主线程return会导致子线程不再执行。
- join可以回收子线程的残余资源。
- detach可以让创建出的子线程在结束时自己回收残余资源。