在传统的UNIX 模型中,当一个进程需要一个实体来完成某事时,他就fork一个子进程去执行处理,UNIX上的大多数网络服务器程序就是这么编写的,正如我们早先讲解的并发服务器程序例子中看到的那样:父进程accept一个连接,fork一个子进程,该子进程处理与该连接对端的客户之间的通信
尽管这种范式多少年来一直用的挺好,fork调用却存在一些问题, fork是昂贵的,fork要把父进程的内存映像复制到子进程,并在子进程中复制所有描述符,如此等等,当今的实现使用称为写时复制(copy-on-write)的技术,用以避免在子进程切实需要自己的副本之前把父进程的数据空间复制到子进程,然而即便有这样的优化措施,fork仍热是昂贵的。
Fork返回之后父子进程之间信息的传递需要进程通信IPC机制,调用Fork之前父进程向尚未存在的子进程传递消息相当容易,因为子进程将从父进程数据空间及所有描述符的一个副本开始运行,然而从子进程往父进程返回信息却比较费力
线程有助于解决这两个问题,线程有时称为轻权进程,因为线程比进程“权重轻些”也就是说,线程的创建可能比进程的创建快10-100倍
同一个进程内的所有的线程共享的相同的全局内存,这使得线程之间易于共享信息,然而伴随这种简易性而来的却是同步问题:
同一进程内的所有线程除了共享全局变量外还共享:
大多数据:
打开的文件(即文件)
信号处理函数和信号处置
当前工作目录
用户ID和组ID,不过每个线程有各自的:
线程ID,寄存器集合,包括程序计数器和栈指针
栈(用于存放局部变量和返回地址)
信号掩码,优先权
基本线程函数:创建和终止
当一个程序由exec启动执行时,称为初始化
线程 (initial thread)或主线程(main thread)的单个线程就创建了,其余线程则由pthread_create函数创建
#include<pthread.h>
int pthread_create(pthread_t * tid, const pthread_attr * attr, void * (* fanc)(void *), void * arg);
// 返回成功则为0.,出错则为正的Exx值
pthread_join 函数
我们可以通过调用pthread_join等待一个给定的线程终止,对比线程和UNIX进程,pthread_create 类似于fork, pthread_join类似于waitpid
#include<pthread.h>
int pthread_join(pthread_t * tid, void ** status)
//返回:若成功则为0,若出错则为正的Errorxx值
pthread_detach 函数
一个线程或者是可汇合的(joinable,默认值)或者是脱离的(detached),当一个可汇合的线程终止时,他的线程ID和退出状态将留存到另一个线程对它调用调用pthread_join, 脱离的线程却像守护进程,当它们终止时,所有相关资源都被释放,我们不能等待它们终止,如果一个线程需要知道另一线程什么时候终止,那就保持第二个线程的可汇合状态
pthread_detach函数把指定的线程转变成为脱离状态
#include<pthread.h>
int pthread_dectach(pthread_t lid);
//返回:若成功则为0,若出粗则为正Error值
pthread_exit函数
让有一个线程终止的方法之一是调用pthread_exit
#include<pthread.h>
void pthread_exit(void * status);
网友评论