2. 线程的创建和终止
(1)创建函数:pthread_create
头文件 |
#include <pthread.h> |
函数 |
int pthread_create(pthread_t* tidp, const pthread_attr_t* attr, void*(*start_rtn)(void*),void* arg); |
返回值 |
成功返回0,否则返回错误编号 |
参数 |
(1)tidp:线程标识符指针 (2)attr:线程属性指针 (3)start_rtn:线程运行函数的起始地址 (4)arg:传递给线程运行函数的参数 |
备注 |
(1)新创建线程从start_rtn函数的地址开始执行 (2)不能保证新线程和调用线程的执行顺序。 |
【编程实验】龟兔赛跑
//pthread_race.c
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <time.h> //实例:龟兔赛跑 //编译选项:gcc -o bin/pthread_race src/pthread_race.c -lpthread //定义线程函数的参数类型 typedef struct { char name[20]; //线程名称 int time; //休眠时间 int start; //起点 int end; //终点 }RaceArg; //定义线程运行函数 void* th_fn(void* arg) { RaceArg* ra = (RaceArg*)arg; int i = ra->start; for(; i<=ra->end; i++){ printf("%s(%lx) run %d\n", ra->name, pthread_self(), i); usleep(ra->time); //time为微秒 } return (void*)(ra->end - ra->start); //返回跑过的路程. //也可以调用pthread_exit((void*)(ra-end - ra-start));来终止线程 } int main(void) { srand48(time(NULL)); //随机种子,对伪随机发生器drand48进行初始化 int err = 0; pthread_t rabbit, turtle; //定义兔子和乌龟线程 //要传递给线程函数的参数(drand48返回值为介于0-1之间的double型随机数) RaceArg r_a = {"rabbit", (int)(drand48() * 10* 1000 * 10), 20, 50}; RaceArg t_a = {"turtle", (int)(drand48() * 10* 1000 * 10), 10, 60}; //创建兔子线程(rabbit) if(err = pthread_create(&rabbit, NULL, th_fn, (void*)&r_a) != 0){ perror("pthread_create error"); } //创建乌龟线程(turtle) if(err = pthread_create(&turtle, NULL, th_fn, (void*)&t_a) != 0){ perror("pthread_create error"); } //等待rabbit线程结束 int* ret = NULL; pthread_join(rabbit, (void**)&ret); //pthread_join(rabbit, NULL);不关心子线程返回值 printf("rabbit's distance is %d\n",(int)ret); //等待turtle线程结束 pthread_join(turtle, (void**)&ret); printf("turtle's distance is %d\n", (int)ret); //pthread_join(turtle, NULL); printf("main thread id: %lx\n", pthread_self()); printf("main thread finished!\n"); return 0; }
(2)线程的终止
①主动终止:线程的执行函数中调用return语句或pthread_exit()
②被动终止:线程可以被同一进程的其它线程取消(调用pthread_cancel(pthid))。
③终止相关的函数
头文件 |
#include <pthread.h> |
函数 |
int pthread_cancel(pthread_t tid); //终止tid线程,tid被动终止 int pthread_exit(void* retval); //主动终止 int pthread_join(pthread_t th, void** thread_return);//等待线程结束 |
返回值 |
成功返回0,否则返回错误编号 |
参数 |
(1)tid:要终止的线程标识符 (2)retval:pthread_exit调用者线程的返回值,可由其他函数和pthread_join来检测获取。 (3)th:pthread_join等待的子线程标识符。 (4)thread_return:用户自定义指针,用来存储被等待线程的返回值。 |
备注 |
(1)pthread_cancel:线程可以被同一进程的其他进程取消。 (2)由于一个进程中的多个线程共享数据段,因此通常在线程退出后,退出线程所占用的资源并不会随线程的结束而释放,所以需要调用pthread_join函数来等待线程结束,类似于wait系统调用。 |
【编程实验】线程的终止
//pthread_term.c
#include <pthread.h> #include <stdio.h> #include <stdlib.h> /*获取线程终止的返回值*/ //定义线程函数的参数 typedef struct { int data1; int data2; }Arg; //定义线程函数 void* th_fn(void* arg) { Arg* ret = (Arg*)arg; //return (void*)(r->data1 + r->data2); return ret; } int main() { int err = 0; pthread_t th; Arg r = {20, 50}; //创建新线程 if((err = pthread_create(&th, NULL, th_fn, (void*)&r)) != 0){ perror("pthread_create error"); } /* //获取子线程的返回值 int* result = NULL; //因为子线程的返回值是void*,当传入pthread_join后 //result本身会被改为子线程返回的值,而不在是NULL。 //这也是传入二级指针的目的,改变result本身的值。 pthread_join(th, (void**)&result); printf("result is %d\n", (int)result); */ //获取子线程的返回值 Arg* result = NULL; pthread_join(th, (void*)&result); printf("result is %d\n", result->data1 + result->data2); return 0; }