线程挂起
若将案例3主函数中的sleep()所在行删除,编译案例,执行程序,则进程会在输出如下信息后便退出:
I am main, I'm a thread!
main_thread_ID = 140186242565888
这是因为,线程与进程类似,若主线程退出,子线程将会无法执行,因此案例1~3中都使用sleep()函数使主线程阻塞,保证子进程能够顺利执行。
在进程中,可以使用wait()、waitpid()将进程挂起,以等待某个子进程结束,而在线程中,则通过pthread_join()函数挂起线程。pthread_join()函数存在于函数库pthread.h中,其函数声明如下:
int pthread_join(pthread_t thread, void **retval);
调用该函数的线程将会使自己挂起,并等待指定进程thread结束。需要注意的是,该线程中指定的线程必须是与调用该函数的线程处于同一个进程中的线程,且多个线程不能同时挂起等待同一个进程,否则pthread_join()将会返回错误。
pthread_join()调用成功将返回0,否则返回errno。pthread_join()中的参数pthread表示被等待的线程id,参数retval用于接收thread线程执行函数的返回值指针,该指针的值与thread线程的终止方式有关:
● 若thread线程通过return返回,retval所指的存储单元中存放的是thread线程函数的返回值;
● 若thread线程被其它线程通过系统调用pthread_cancel()异常终止,retval所指向的存储单元中存放的是常量PTHREAD_CANCELED;
● 若thread线程通过自调用pthread_exit()终止,retval所指向的存储单元中存放的是pthread_exit()中的参数ret_val;
● 此外,若等待thread的线程不关心它的终止状态,可以将retval的值设置为NULL。
一般在使用线程时,都使用pthread_exit()函数将其终止。下面通过一个简单案例来展示含参pthread_exit()函数的用法。
案例5:使用pthread_exit()退出线程,为线程设置退出状态,并将线程的退出状态输出。
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <pthread.h>
4 #include <stdlib.h>
5 typedef struct{
6 int a;
7 int b;
8 } exit_t;
9 void *tfn(void *arg)
10 {
11 exit_t *ret;
12 ret = malloc(sizeof(exit_t));
13 ret->a = 100;
14 ret->b = 300;
15 pthread_exit((void *)ret); //线程终止
16 return NULL; //线程返回
17 }
18 int main(void)
19 {
20 pthread_t tid;
21 exit_t *retval;
22 pthread_create(&tid, NULL, tfn, NULL);
23 //调用pthread_join可以获取线程的退出状态
24 pthread_join(tid, (void **)&retval);
25 printf("a = %d, b = %d \n", retval->a, retval->b);
26 return 0;
27 }
在案例5创建的子线程中,既调用了pthread_exit()函数,又设置了关键字return;在程序的第24行,使用pthread_join()等待子线程退出,并获取线程的退出状态,若第25行代码中打印的线程退出状态不为空,说明线程通过pthread_exit()函数退出。
编译案例5,执行程序,执行结果如下:
a = 100, b = 300
由执行结果可知,第15行调用的pthread_exit()函数成功使线程退出,并设置了线程的退出状态。
进程中可以使用waitpid()函数结合循环结构使主进程等待多个进程退出,线程中的pthread_join()同样可以与循环结构结合,等待多个线程退出。
案例6:使用pthread_join()回收多个子线程,并使用pthread_exit()获取每个线程的退出状态。
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <pthread.h>
5 long int var = 100;
6 void *tfn(void *arg)
7 {
8 long int i;
9 i = (long int)arg;
10 sleep(i);
11 if (i == 1) {
12 var = 333;
13 printf("var = %d\n", var);
14 pthread_exit((void *)var);
15 }
16 else if (i == 3) {
17 var = 777;
18 printf("I'm %dth pthread, pthread_id = %lu\n"
19 " var = %d\n", i+1, pthread_self(), var);
20 pthread_exit((void *)var);
21 }
22 else {
23 printf("I'm %dth pthread, pthread_id = %lu\n"
24 " var = %d\n", i+1, pthread_self(), var);
25 pthread_exit((void *)var);
26 }
27 return NULL;
28 }
29 int main(void)
30 {
31 pthread_t tid[5];
32 long int i;
33 int *ret[5];
34 for (i = 0; i < 5; i++) //创建子线程
35 pthread_create(&tid[i], NULL, tfn, (void *)i);
36 for (i = 0; i < 5; i++) { //回收子线程
37 pthread_join(tid[i], (void **)&ret[i]);
38 printf("-------%d 's ret = %d\n", i, (long int)ret[i]);
39 }
40 printf("I'm main pthread tid = %lu\t var = %d\n", pthread_self(), var);
41 pthread_exit(NULL);
42 }
编译案例6,执行程序,执行结果如下:
I'm 1th pthread, pthread_id = 140602948568832
var = 100
-------0 's ret = 100
var = 333
-------1 's ret = 333
I'm 3th pthread, pthread_id = 140602927589120
var = 333
-------2 's ret = 333
I'm 4th pthread, pthread_id = 140602917099264
var = 777
-------3 's ret = 777
I'm 5th pthread, pthread_id = 140602906609408
var = 777
-------4 's ret = 777
I'm main pthread tid = 140602948577024 var = 777
由执行结果可知,程序中创建的5个子线程都成功退出,案例6成功实现。