1、进程与线程
什么是线程?
- 在一个程序里的一个执行路线就叫做线程,即线程是“一个进程内部的控制序列”
- 一切进程至少都有一个执行线程
- 线程在进程内部运行,本质是在进程地址空间内运行
- 在Linux系统中,在cpu眼中,看到的pcb都要比传统的进程更加轻量化
- 线程是一个执行流,用来运行代码,处理数据。
线程概念:
- 先说进程:在传统操作系统中使用pcb来描述一个程序的运行---pcb就是进程
- Linux下pcb用来模拟实现线程,因此Linux下的pcb实际是一个轻量级进程LWP,即线程
- 这个轻量级进程因为共用大部分进程资源,相较于传统的进程更加轻量化。
线程的优点:
- 创建一个新线程的代价要比创建一个新进程小得多
- 与进程之间的切换相比,线程之间的切换需要操作系统做的工作更少
- 线程占用的资源要比进程少很多
- 能充分利用多处理器的可并行数量
- 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
- 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
- I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。
线程的缺点:
- 性能损失:一个很少被外部事件阻塞的计算密集型线程往往无法与其他线程共享同一个处理器
- 健壮性降低:编写多线程需要更全面更深入的考虑,线程之间是缺乏保护的。
- 缺乏访问控制:在一个线程中调用某些OS函数会对整个进程造成影响。
- 编程难度提高
线程之间资源的独有与共享:
- 独有:栈、寄存器、信号屏蔽字、errno、线程ID、调度优先级
- 共享:共享虚拟地址空间、文件描述符表、信号处理方式、当前工作路径、用户ID/组ID
那么,对于多任务的执行----可以使用多进程也可以使用多线程,哪一个更好?
首先分析多进程与多线程的优缺点---->结合具体使用场景来定
对于shell这种对主程序稳定安全性要求更高的程序就需要使用多进程,创建子进程,让其处理任务。
进程和线程的关系:
2、Linux线程控制
线程控制:线程创建/线程终止/线程等待/线程分离
POSIX线程库
- 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的
- 要使用这些库函数,要通过引入头文件<pthread.h>
- 链接这些线程函数库时,要使用编译器命令的"-lpthread"选项
线程创建:
原型:int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void*),void *arg);
参数:thread:返回线程ID--线程地址空间在整个虚拟地址空间中的首地址 attr:设置线程的属性,为NULL表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数 arg:传给线程启动函数的参数
返回值:成功返回0,失败返回错误码
线程终止:
return 不能在main函数中return(退出的是进程,会导致所有线程退出)
void pthread_exit(void *retval);退出线程自身,谁调用谁退出 参数retval:线程的退出返回值
int pthread_cancel(pthread_t thread);取消其他线程;让其他线程退出 参数thread:要取消的线程ID
主线程退出,其它线程依然可以正常运行。
线程等待:
为什么需要线程等待?
- 已经退出的线程,其空间没有被释放,仍然在进程的地址空间内
- 创建新的线程不会复用刚才退出线程的地址空间
一个线程创建出来,默认有一个属性joinable;处于joinable属性的线程退出后,不会自动释放资源,需要被其他线程等待,才能释放资源。
int pthread_join(pthread_t thread,void **reval);功能:阻塞等待指定线程退出,通过retval获取返回值。
线程分离:
将线程的joinable属性修改为detach属性。处于detach属性的线程,退出后自动回收资源,意味着这个线程不需要被等待;线程分离的使用场景:对线程的返回值不关心的情况下。
pthread_detach(pthread_t tid)