Linux线程函数原型是这样的:
1 void* thread_fun(void* arg)
它的返回值是 空类型指针,入口参数也是 空类型指针。那么线程的 exit code 也应该是 void * 类型的。但是在主线程怎么捕获子线程的 exit code 并使用的呢?
捕获的思路如下:
1. 在主线程中定义一个 void* tret;
2. 使用 pthread_join(tidxx, &tret);
这样就能够捕获到子线程的 exit code。
但是如何使用呢?这就取决于子线程中的 exit code 具体表示的数据类型了,可以是 int, char *, struct xxxStr 等等,然后直接在主线程中使用类型转换到对应的数据类型就行了。
例如:
1 /**************************************************************** 2 # File Name: thread_cleanup2.c 3 # Author : lintex9527 4 # E-Mail : lintex9527@yeah.net 5 # Created Time: Sat 22 Aug 2015 11:01:59 AM HKT 6 # Purpose : 7 # Outline : 8 # Usage : 9 # -------------------------------------------------- 10 # Result : 11 # -------------------------------------------------- 12 *****************************************************************/ 13 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <pthread.h> 17 18 void* thr_fn01(void *arg) 19 { 20 printf("thread 1 start:\n"); 21 pthread_exit((void *)100); 22 pthread_exit((void *)"SOT-26"); // the first pthread_exit() works, the rest below that does not execute. 23 } 24 25 void* thr_fn02(void *arg) 26 { 27 printf("thread 2 start:\n"); 28 pthread_exit((void *)"SOT-363"); 29 } 30 31 int main(void) 32 { 33 int err; 34 pthread_t tid1, tid2; 35 void *tret; 36 37 pthread_create(&tid1, NULL, thr_fn01, (void *)1); 38 pthread_join(tid1, &tret); 39 printf("thread 1 exit code: %d\n", (tret)); 40 printf("thread 1 exit code: %d\n", (int *)(tret)); 41 42 pthread_create(&tid2, NULL, thr_fn02, (void *)1); 43 pthread_join(tid2, &tret); 44 printf("thread 2 exit code: %s\n", (tret)); 45 printf("thread 2 exit code: %s\n", (char *)(tret)); 46 47 return 0; 48 }
执行的结果如下:
$ ./thread_cleanup2.exe thread 1 start: thread 1 exit code: 100 thread 1 exit code: 100 thread 2 start: thread 2 exit code: SOT-363 thread 2 exit code: SOT-363
可以看到“直接使用指针方式” 和 “强制类型转换方式” 输出的结果都一样。
上面的都是基本数据类型方式,那么再试一下其他的数据类型,例如结构体:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <pthread.h> 5 6 7 struct personStr{ 8 char name[30]; 9 unsigned int age; 10 char sex; // 'M', 'W' 11 char ID[30]; 12 }; 13 14 void printPerson(const char * str, struct personStr *p) 15 { 16 printf("%s\n", str); 17 printf(" name:%s\n", p->name); 18 printf(" age: %d\n", p->age); 19 printf(" sex: %c\n", p->sex); 20 printf(" ID: %s\n", p->ID); 21 } 22 23 struct personStr thisman; 24 25 void* thr_fn01(void *arg) 26 { 27 printf("thread 1 start:\n"); 28 memcpy(thisman.name, "Lee", strlen("Lee")); 29 thisman.age = 33; 30 thisman.sex = 'M'; 31 memcpy(thisman.ID, "421127xxxx78455623", strlen("421127xxxx78455623")); 32 printPerson("In pthread 1:", &thisman); 33 34 pthread_exit((void *)&thisman); 35 } 36 37 void* thr_fn02(void *arg) 38 { 39 printf("thread 2 start:\n"); 40 pthread_exit((void *)"SOT-363"); 41 42 } 43 44 int main(void) 45 { 46 int err; 47 pthread_t tid1, tid2; 48 void *tret; 49 50 err = pthread_create(&tid1, NULL, thr_fn01, (void *)1); 51 pthread_join(tid1, &tret); 52 printPerson("In main thread:", tret); // 直接使用指针 53 printPerson("In main thread:", (struct personStr *)tret); // 强制类型转换为结构体指针 54 55 err = pthread_create(&tid2, NULL, thr_fn02, (void *)1); 56 pthread_join(tid2, &tret); 57 printf("thread 2 exit code: %s\n", (tret)); 58 printf("thread 2 exit code: %s\n", (char *)(tret)); 59 60 return 0; 61 }
执行结果如下:
$ ./thread_cleanup2.exe thread 1 start: In pthread 1: name:Lee age: 33 sex: M ID: 421127xxxx78455623 In main thread: name:Lee age: 33 sex: M ID: 421127xxxx78455623 In main thread: name:Lee age: 33 sex: M ID: 421127xxxx78455623 thread 2 start: thread 2 exit code: SOT-363 thread 2 exit code: SOT-363
可以看到 “直接使用指针” 和 “强制类型转换”结果都是一样的。如果图方便就直接使用指针,而且这样的代码通用性也好,万一将来某天结构体名字变动了,就需要改动很多地方了,但是也有弊病,就是代码的易读性不好。
有一点奇怪的就是第一个例子中,为什么返回的是整数 int 类型的"100",却能通过指针打印出"100"呢?
这样验证:
printf("thread 1 exit code: %d\nsizeof tret is %d Bytes\nsizeof(int) is %d Bytes.\n", (tret), sizeof(tret), sizeof(int));
结果是这样的:
thread 1 exit code: 100 sizeof tret is 8 Bytes sizeof(int) is 4 Bytes.
那么就说明 tret 的确是指针类型的,占用了8个字节的数据,而 int 类型的数据只占用了4个字节,而且进行如下的尝试,编译失败了:
printf("tret * 3 = %d\n", tret * 3); 很不幸,失败了,结果: thread_cleanup2.c:93: error: invalid operands to binary * (have ‘void *’ and ‘int’) make: *** [thread_cleanup2.o] Error 1
如果的确是想使用 tret 的值100, 可否通过指针取值运算呢?
printf("tret * 3 = %d\n", (*((int *)tret)) * 3); 很不幸,这样也失败了。
如果要想把返回值 tret 参与其他的运算,就必须使用一个转换的桥梁。利用 “中间变量 = tret”,然后使用这个中间变量,虽然编译会有 warning 提醒,但是的确能使用:
//printf("tret * 3 = %d\n", (*((int *)tret)) * 3);// failed. //int num = *((int *)tret); // failed. int num = tret; printf("num = %d, num * 3 = %d\n", num, num * 3 );
编译提示:
thread_cleanup2.c:95: warning: initialization makes integer from pointer without a cast
cc -o thread_cleanup2.exe thread_cleanup2.o -lpthread
运行结果:
thread 1 exit code: 100
sizeof tret is 8 Bytes
sizeof(int) is 4 Bytes.
num = 100, num * 3 = 30
2015-08-22 13:17:12 于公司。