Linux系统编程——进程和线程的区别与联系

 在许多经典的操作系统教科书中,总是把进程定义为程序的执行实例,它并不执行什么, 只是维护应用程序所需的各种资源,而线程则是真正的执行实体。

 为了让进程完成一定的工作,进程必须至少包含一个线程。

                image.png

LWP:light weight process 轻量级的进程,本质上仍然是进程(Linux)下

Linux 内核线程实现原理:

 类 Unix 系统中,早期是没有 “线程” 概念的,80年代引入,借助进程机制实现出可线程的概念,因此这类系统中,进程和线程密切相关

  1. 轻量级进程,也有 PCB ,创建线程使用的底层函数与进程一样,都是 clone
  2. 从内核里看进程和线程是一样的,都有各自不同的 PCB 进程控制块,但是 PCB 中指向内存资源的三级页表是相同的
  3. 进程可以蜕变成线程
  4. 线程可看作寄存器与栈(内核栈+用户栈)的集合
  5. 通过 ps -Lf 查看 LWP


 进程,直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己的地址空间,有自己的堆,上级挂靠单位是操作系统。操作系统会以进程为单位,分配系统资源,所以我们也说,进程是资源分配的最小单位

 线程存在与进程当中,是操作系统调度执行的最小单位。说通俗点,线程就是干活的。

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源

如果说进程是一个资源管家,负责从主人那里要资源的话,那么线程就是干活的苦力。一个管家必须完成一项工作,就需要最少一个苦力,也就是说,一个进程最少包含一个线程,也可以包含多个线程。苦力要干活,就需要依托于管家,所以说一个线程,必须属于某一个进程。进程有自己的地址空间,线程使用进程的地址空间,也就是说,进程里的资源,线程都是有权访问的,比如说堆啊,栈啊,静态存储区什么的。

 线程就是个无产阶级,但无产阶级干活,总得有自己的劳动工具吧,这个劳动工具就是栈,线程有自己的栈,这个栈仍然是使用进程的地址空间,只是这块空间被线程标记为了栈。每个线程都会有自己私有的栈,这个栈是不可以被其他线程所访问的。

 进程所维护的是程序所包含的资源(静态资源), 如:地址空间,打开的文件句柄集,文件系统状态,信号处理handler,等;

 线程所维护的运行相关的资源(动态资源),如:运行栈,调度相关的控制信息,待处理的信号集,等;

总结如下

进程线程
有独立的地址空间没有独立的地址空间,与进程内其他线程共享
有独立的 PCB有独立的 PCB
最小的资源分配单位最小的执行单位

线程与线程之间

共享:

  • 文件描述符表
  • 每种信号的处理方式
  • 当前工作目录
  • 用户 ID 与 组 ID
  • 内存地址空间(.text/.data/.bss/heap/共享库)

独享:

  • 线程 ID
  • 栈空间(用户栈, 内核栈)
  • errno 变量
  • 信号屏蔽字
  • 调度优先级

线程优缺点

优点:

  • 开销小
  • 提高程序并发性
  • 数据通信,共享数据方便

缺点:

  • 库函数,不稳定
  • 对信号的支持不好
  • 调试、编写困难,不支持 gdb 调试

线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。