线程基础

进程与线程

进程是一个线程组,线程是进程中的一条执行流(如,一个进程中的main函数,是由线程执行起来的),这个执行流在linux下是通过pcb实现的,所以linux下线程就是一个pcb,一个进程中的线程公用同一个虚拟地址空间,相较与传统pcb更加轻量化,也被称为轻量级进程。操作系统资源分配是直接分配给整个线程组,这个线程组就是进程,所以进程是资源分配的基本单位,而线程是进程实际运作的基本单位,cpu通过调度pcb来实现程序的调度,所以线程是调度的基本单位,ps -L中LWP为轻量级进程id,pid为这个线程组id
一个进程中的线程共享:

  1. 同一虚拟地址空间:本质共享同一页表
  2. 文件描述符表:一个线程修改了一个文件,其他的线程访问到的文件也都改变
  3. 每种信号的处理方式(SIG_IGN、SIG_DFL或者自定义的信号处理函数)
  4. 未决信号集:只要进程收到了信号,也就意味着所有线程收到了信号
  5. 当前工作目录、用户id和组id

由于进程中的各个线程共用同一个虚拟地址空间,为了保证程序的合理性所以各个线程有自己的信息:

  1. 线程ID
  2. 栈:防止调用栈混乱
  3. 一组寄存器:线程的上下文信息
  4. errno:防止线程的errno被另一个线程覆盖
  5. 信号屏蔽字:防止线程在执行重要操作时被打断
  6. 调度优先级:各线程要被调度,就必须有优先级

线程的优/缺点

优点:

  • 线程的创建与销毁成本更低,创建一个进程,我们需要给他分配虚拟地址空间,这个空间占用了一部分资源。创建一个线程,不需要分配虚拟地址空间,节约资源,增快了效率,销毁也比较快
  • 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多,不需要切换页表,只用切换一小部分数据,效率较高
  • 由于线程组中线程公用同一虚拟地址空间,所以相比进程线程间通信比较方便,只需知道地址就能访问同一空间
  • 能充分利用多处理器的可并行数量,比如4核CPU,需要不停歇的进行CPU的运算操作,用四个线程运算操作,CPU占用率可达到400%(Linux下)充分利用了硬件资源,处理CPU密集型程序通常执行流个数为CPU核心数+1,若创建线程很多而CPU资源不够多,则大量进程切换调度成本会提高
  • I/O密集型应用,为了提高性能,将I/O操作重叠,多任务并行处理,多磁盘可以实现同时处理,线程可以同时等待不同的I/O操作

缺点:

  • 缺乏保护访问控制、健壮性降低,需要考虑线程安全问题,异常以及系统调用exit会直接针对整个进程
  • 性能损失,若CPU密集型程序线程的数量比可用的处理器多则增加了额外的同步和调度开销