1、线程概念
LWP:light weight process轻量级的进程,本质上是进程(在LINUX环境下)
进程:独立地址空间,拥有PCB
线程:也有PCB,但没有独立的地址空间(共享)
区别:是否具有共享地址空间 独居:进程 群租:线程
LINUX:线程:最小的执行单位
进程:最小的分配资源单位,可以看成只有一个线程的进程单位
2、Linux内核线程实现原理
1)轻量级进程,创建底层和进程一样调用Clone
2)从内核看都一样,两者都使用PCB,但是PCB中指向内存资源的三级页表是相同的
3)进程可以蜕变成线程
4)线程可以看作是寄存器和栈的集合
5)在LINUX下,线程是最小执行单位,进程是最小分配资源单位
查看LWP号 ps -Lf pid 线程号(不是线程ID)
3、线程共享资源
1)文件描述符表
2)每种信号的处理方式
3)当前工作目录
4)用户ID和组ID
5)内存地址空间(.text/.data/.bss/heap/共享库)
4、线程非共享资源
1)线程ID
2)处理器现场和栈指针(内核栈)
3)独立的栈空间(用户空间栈)
4)errno变量
5)信号屏蔽字
6)调度优先级
5、线程优缺点
优点:1、提高程序并发性 2、开销小 3、数据通信、共享数据方便
缺点:1、库函数、不稳定 2、调试、编码困难,GDB不支持 3、对信号支持不好
6、线程控制原语
pthread_self:获取线程ID
pthread_create:创建线程
线程之间共享全局变量,进程之间不共享全局变量!!!
pthread_exit()将单个线程退出
return 返回调用者
exit()退出进程
pthread_join():阻塞等待线程退出,获取线程的退出状态
pthread_detach():实现线程分离:自动清理PCB
线程分离状态:指定该状态,线程主动与主线程断开关系。线程结束后,其退出状态不由其他线程获取,而直接自己自动释放。网络、多线程服务器常用。在创建线程的时候可以改变线程属性为分离态
pthread_cancel():杀死取消线程
线程的取消并不是实时的,而有一定的延时。需等待线程到达某个取消点(检查点)
取消点:要么是系统调用man 7 pthreads 查看/
或者自己就设置一个取消点:
使用库函数:pthread_testcancel()
pthread_equal():判断两个线程ID是否相等
7、线程属性
主要结构体成员:
1、线程分离状态
2、线程栈大小(默认平均分配)
3、线程警戒缓冲区大小(位于栈末尾)
线程属性初始化:pthread_attr_init()
销毁线程属性所占空间:pthread_attr_destroy()
线程分离态设置:pthread_attr_setdetachstate()
获取分离态是或否:pthreat_attr_getdetachstate()
设置一个线程分离,这个线程运行的太快,可能pthread_create函数还没返回线程就已经结束了,它结束以后线程号和系统资源会移交给其他函数,这样pthread_create函数返回出错,在子线程里调用pthread_cond_timewait函数让线程等待一会,注意不能调用wait()函数,该函数是令整个进程睡眠,不能解决线程同步问题
线程栈地址:pthread_attr_setstack():当进程栈地址空间不足时,指定新线程使用由malloc分配的空间作为自己的栈空间pthread_attr_getstack()可以获取线程栈地址
线程栈大小:pthread_attr_setstacksize() pthread_attr_getstacksize()
NPTL:线程版本
8、线程注意事项
1)主线程退出,其他线程不退出调用pthread_exit()
2)避免僵尸线程:pthread_detach() pthread_join() 创建时设立分离态
3)malloc 和mmap申请的内存可以被其他线程释放掉
4)应该避免在多线程模型中调用fork除非马上exec,一个进程中多个线程,只有调用fork()的线程存在,其他线程在子进程中均pthread_exit()没了
5)信号的复杂语义很难和多进程共存,应避免引入信号机制