UNIX线程
转自:http://blog.csdn.net/yang_yulei/article/details/17595901
单个控制线程的进程在同一时刻只做一件事情,有了多个控制线程以后,在程序设计时可以把进程设计成在同一时刻能够做不止一件事,每个线程处理各自独立的任务。
使用多线程的好处:
1、 通过为每种事件类型的处理分配单独的线程,能够简化处理异步事件的代码。
2、 多个进程必须使用操作系统提供的复杂机制才能实现内存和文件描述符的共享,而多个线程自动地可以访问相同的存储空间和文件描述符。
3、 有了多线程,相互独立的任务的处理可以交叉进行,只需要为每个任务分配一个单独的线程。改善整个程序的吞吐量。
4、 交互的程序同样可以通过使用多线程实现响应时间的改善。
不管处理器的个数是多少,程序可以通过使用线程得以简化。而且,即使多线程程序在串行化任务时不得不阻塞,由于某些线程在阻塞的时候还有另外一些线程可以运行,所以多线程程序在单处理器上运行仍然能够改善响应时间和吞吐量。
【进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序的全局内存和堆内存、栈以及文件描述符。】
线程标识
进程ID在整个系统中是唯一的,但线程ID不同,线程ID只在它所属的进程环境中有效。
线程可以通过调用pthread_self函数获得自身的线程ID。
(注意:linux默认不连接pthread库,故在编译时要手动链接:gcc test.c -l pthread.h)
#include <pthread.h>
pthread_t pthread_self (void) ;
线程ID则用pthread_t数据类型来表示,实现的时候可用一个结构来代表pthread_t数据类型,因此必须使用函数来对两个线程ID进行比较。
#include <pthread.h>
int pthread_equal (pthread_t tid1, pthread tid2) ;
若相等则返回非0值,否则返回0.
线程创建
在创建多个控制线程以前,程序的行为与传统的进程并没有什么区别。新增的线程可以通过调用pthread_create函数创建。
#include <pthread.h>
int pthread_create(pthread_t * tidp, //线程ID指针
const pthread_attr_t * attr, //线程属性指针
void *(*start_rtn)(void *), //线程函数
void * arg //线程函数参数结构指针) ;
新创建的线程从start_rtn函数的地址开始运行。该函数只有一个无类型指针参数arg,如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg参数传入。
注意:pthread函数在调用失败时通常会返回错误码,它们并不像其他的POSIX函数一样设置errno。
线程函数一定要形如:void* func(void* arg) 才可以无警告编译通过
线程终止
如果进程中的任一线程调用了exit,_Exit或_exit,那么整个进程就会终止。
单个线程可以通过下列三种方式退出,在不终止整个进程的情况下停止它的控制流。
1、 线程从启动例程中返回。(函数执行完,自然退出)
2、 线程被同一进程中的其他线程取消。
3、 线程调用pthread_exit。
#include <pthread.h>
void pthead_exit(void * rval_ptr) ;
rval_ptr指向线程的返回码,若线程被取消,则返回码为PTHEAD_CANCELED。
进程中的其他线程可通过调用pthread_join函数访问到这个指针。(即获取进程的终止状态)
#include <pthread.h>
int pthread_join(pthread_t tid, void** rval_ptr) ;
调用线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。
线程可以通过调用pthread_cancel函数来请求取消同一进程中的其他线程。
#include <pthread.h>
int pthread_cancel(pthread_t tid) ;
被要求取消的线程可以选择忽略请求,或控制取消方式
线程清理处理程序
线程可以建立多个清理处理程序。记录在栈中,即它们的执行顺序与它们注册顺序相反。(进程的清理处理函数也是如此)
#include <pthread.h>
void pthread_cleanup_push(void(*rtn)(void *), void *arg) ;
void pthread_cleanup_pop(int execute) ;
清理函数被执行当:
① 调用pthread_exit时
② 响应取消请求时
③ 调用pthread_cleanup_pop时(参数execute不为0)
注意:pthread_cleanup_push与pthread_cleanup_pop在一个函数中要配对使用,否则会编译出错。若想让线程在退出时自动执行清理函数,则在配对使用时,pthread_cleanup_pop(0);把pop的参数置为0,则清理函数不被其调用。
注意:若线程是自然终止或是return而终止的,那么它的清理处理函数就不会被调用。(这点与进程的清理处理函数不同)
- //线程退出清理函数
- //
- #include <pthread.h>
- #include <stdio.h>
- #include <errno.h>
- #include <stdlib.h>
- void cleanup(void* arg);
- void* thr_fn1(void* arg);
- void* thr_fn2(void* arg) ;
- int
- main(void)
- {
- pthread_t tid1, tid2;
- void* tret ;
- if (pthread_create(&tid1, NULL, thr_fn1, (void*)0) != 0)
- perror("can't create thread1 \n") ;
- if (pthread_create(&tid2, NULL, thr_fn2, (void*)0) != 0)
- perror("can't create thread1 \n") ;
- pthread_join(tid1, &tret) ;
- printf("thread 1 exit code %d\n", (int)tret) ;
- pthread_join(tid2, &tret) ;
- printf("thread 2 exit code %d\n", (int)tret) ;
- exit(0) ;
- }
- void
- cleanup(void* arg)
- {
- printf("cleanup: %s\n", (char*)arg) ;
- }
- void*
- thr_fn1(void* arg)
- {
- printf("thread 1 start\n") ;
- pthread_cleanup_push(cleanup, "thread 1 first handler") ;
- pthread_cleanup_push(cleanup, "thread 1 second handler") ;
- printf("thread 1 push complete\n") ;
- pthread_cleanup_pop(0) ;
- pthread_cleanup_pop(0) ;
- return ((void*)1) ;
- }
- void*
- thr_fn2(void* arg)
- {
- printf("thread 2 start\n") ;
- pthread_cleanup_push(cleanup, "thread 2 first handler") ;
- pthread_cleanup_push(cleanup, "thread 2 second handler") ;
- printf("thread 2 push complete\n") ;
- pthread_cleanup_pop(0) ;
- pthread_cleanup_pop(0) ;
- pthread_exit ((void*)2) ;
- }
进程原语 | 线程原语 | 描述 |
getpid | pthread_self | 获取控制流的ID |
fork | pthread_create | 创建新的控制流 |
exit | pthread_exit | 从现有的控制流中退出 |
waitpid | pthread_join | 从控制流中得到退出状态 |
atexit | pthread_cleanup_push | 注册退出清理函数 |
abort | pthread_cancel | 请求退出流的非正常退出 |