1. pthread_create
1. #include <pthread.h> 2. 3. int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 4. 5. 6. pthread_t *thread:传递一个pthread_t变量地址进来,用于保存新线程的tid(线程ID) 7. 8. const pthread_attr_t *attr:线程属性设置,如使用默认属性,则传NULL 9. 10. void *(*start_routine) (void *):函数指针,指向新线程应该加载执行的函数模块 11. 12. void *arg:指定线程将要加载调用的那个函数的参数
返回值:成功返回0,失败返回错误号。以前学过的系统函数都是成功返回0,失败返回-1,而错误号保存在全局变量errno中,而pthread库的函数都是通过返回值返回错误号,虽然每个线程也都有一个errno,但这是为了兼容其它函数接口而提供的,pthread库本身并不使用它,通过返回值返回错误码更加清晰。
在一个线程中调用pthread_create()创建新的线程后,当前线程从pthread_create()返回继续往下执行,而新的线程所执行的代码由我们传给pthread_create的函数指针start_routine决定。
2. pthread_self
1. #include <pthread.h> 2. 3. pthread_t pthread_self(void);
获取调用线程tid,其作用对应进程中getpid()函数。
线程ID:pthread_t类型,其本质是在Linux下是无符号整数,其他系统中可能是结构体实现
线程ID是进程内部识别标志。(两个进程间,线程ID允许相同)
注意:不应该使用全局变量pthread_t tid,在子进程中通过pthread_create传出参数来获取线程ID,而应该使用pthread_self()
线程ID与线程号的区别:
Ps –eLf命令看到的LWP那一列是线程号,线程号是CPU分配时间轮片的依据
Pthread_self得到的是线程ID,线程ID用来在进程内部区分线程
程序1:循坏创建多个子线程
1. #include <stdio.h> 2. #include <string.h> 3. #include <unistd.h> 4. #include <stdlib.h> 5. #include <pthread.h> 6. 7. void *thread_func(void *arg) 8. { 9. int i = (int )arg; 10. sleep(i); 11. printf("%dth thread: thread id = %lu, pid = %u\n", i+1, pthread_self(), getpid()); 12. 13. return NULL; 14. } 15. 16. int main(void) 17. { 18. pthread_t tid; 19. int ret, i; 20. 21. for(i=0; i<5; i++){ 22. ret = pthread_create(&tid, NULL, thread_func, (void *)i); 23. if(ret != 0){ 24. fprintf(stderr, "pthread_create error:%s\n", strerror(ret)); 25. exit(1); 26. } 27. } 28. 29. //sleep(i); 30. 31. //return 0; //将当前进程退出 32. pthread_exit(NULL); 33. 34. }
执行结果如下:
线程默认共享数据段、代码段等地址空间,常用的是全局变量,而进程不共享全局变量,只能借助mmap.
程序2:验证线程之间共享全局数据
1. #include <stdio.h> 2. #include <string.h> 3. #include <unistd.h> 4. #include <stdlib.h> 5. #include <pthread.h> 6. 7. int var = 100; 8. 9. void *tfn(void *arg) 10. { 11. var = 200; 12. printf("thread.\n"); 13. 14. return NULL; 15. } 16. 17. int main(void) 18. { 19. printf("At first var = %d.\n", var); 20. 21. pthread_t tid; 22. pthread_create(&tid, NULL, tfn, NULL); 23. sleep(1); 24. 25. printf("after pthread_create, var = %d.\n", var); 26. 27. return 0; //将当前进程退出 28. 29. }
执行结果如下:
主控线程先结束,其他子线程也不会在执行 。如果任意一个线程调用了exit或_exit,则整个进程的所有线程都终止。
3. pthread_exit
1. #include <pthread.h> 2. 3. void pthread_exit(void *retval);
void *retval:线程退出时传递出的参数,可以是退出值或地址,如是地址时,不能是线程内部申请的局部地址。一般传NULL。
pthread_exit与exit的区别:
调用线程退出函数pthread_exit,只是推出当前线程
任何线程里使用exit都会导致进程退出,主控线程退出时不能return或exit,因为会影响其他线程未工作。
exit与_exit的区别:
exit关闭C标准文件流,并刷新文件缓冲区
_exit(Linux底层函数),导致进程退出,关闭未关闭的文件描述符
需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
4. pthread_join
阻塞等待线程退出,获取线程退出状态,其作用对应进程中的waitpid()函数
1. #include <pthread.h> 2. 3. int pthread_join(pthread_t thread, void **retval);
pthread_t thread:回收线程的tid
void **retval:接收退出线程传递出的返回值
返回值:成功返回0,失败返回错误号
回收一个线程,获得线程退出值,如果线程没有终止,阻塞等待线程退出
5. pthread_cancel
在进程内的某个线程可以取消另一个线程
1. #include <pthread.h> 2. 3. int pthread_cancel(pthread_t thread);
来一段code熟悉下刚才的API
1. #include <stdio.h> 2. #include <stdlib.h> 3. #include <pthread.h> 4. #include <unistd.h> 5. 6. void *thr_fn1(void *arg) 7. { 8. printf("thread 1 returing\n"); 9. return (void *) 1; 10. } 11. 12. void *thr_fn2(void * arg) 13. { 14. printf("thread 2 exiting\n"); 15. pthread_exit((void * )2); 16. } 17. 18. 19. void *thr_fn3(void * arg) 20. { 21. while(1) 22. { 23. printf("thread3 writing\n"); 24. sleep(1); 25. } 26. } 27. 28. int main(void) 29. { 30. pthread_t tid; 31. void * tret; 32. 33. pthread_create(&tid, NULL, thr_fn1, NULL); 34. pthread_join(tid, &tret); 35. printf("thread 1 exit code %d\n", (int )tret); 36. 37. pthread_create(&tid, NULL, thr_fn2, NULL); 38. pthread_join(tid, &tret); 39. printf("thread 2 exit code %d\n", (int )tret); 40. 41. pthread_create(&tid, NULL, thr_fn3, NULL); 42. sleep(3); 43. pthread_cancel(tid); 44. pthread_join(tid, &tret); 45. 46. return 0; 47. }
执行结果如下:
6. pthread_detach
1. #include <pthread.h> 2. 3. int pthread_detach(pthread_t tid);
pthread_t tid:分离线程tid
返回值:成功返回0,失败返回错误号。
一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL。如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。
7. pthread_equal
比较两个线程是否相等
线程终止方式
如果需要只终止某个线程而不终止整个进程,可以有三种方法:
1.从线程主函数return。这种方法对主控线程不适用,从main函数return相当于调用exit。
2.一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
3.线程可以调用pthread_exit终止自己