1 进程
1.1 进程概念
进程:操作系统提供的一种抽象,当程序在运行时,好像计算机的所有硬件资源都在为其服务。换言之,进程就是程序的一次运行过程。进程是操作系统分配资源的基本单位。
注意:区分进程和程序(可执行文件)
程序即可执行文件,是静态的,存储在磁盘中。
打开任务管理器,在进程界面显示的是一个个正在运行的程序,即进程,也就是说进程是动态的,当可执行文件被加载到内存中,并开始执行程序的代码,就形成了进程。
1.2 进程控制块PCB
PCB:进程控制块,内部包含pid(进程唯一标识)、进程关联的程序基本信息(程序信息、内存指针等)、进程分配资源信息、进程调度信息。每一个PCB对象,表示一个进程,也就是一个运行的程序。
在PCB中,包含一个文件描述符表(进程打开(fopen)了哪些文件),文件描述符表可以理解为一个顺序表,下标索引就是文件描述符,索引对应的内容就是对应的文件。
进程的调度信息包含:进程优先级、进程状态(就绪、阻塞等等)、进程记账信息(每次在CPU的执行时间,方便操作系统调度策略的调整)和进程上下文(进程在执行过程中可能随时被调度离开,此时需要保存进程的上下文,也就是“存档”,便于下次执行时“读档”)。
1.3 进程虚拟地址
在操作系统中,我们不希望一个进程的运行状态影响到另一个进程,因此就需要进程具有“隔离性”,进程的虚拟地址空间是保证进程“隔离性”的重要原因。
如果没有虚拟地址空间,进程在对内存指针进行访问时,有可能出现指针指向错误地址的问题,那么就有可能出现进程1访问到进程2的数据,导致操作系统的不稳定。
通过引入虚拟地址空间,每一个进程的虚拟地址空间相互独立,比如进程1的代码中访问到变量a,进程2的代码中也访问到变量a,但是这两个变量a的值不同,其在各自虚拟地址空间的地址相同,通过MMU(内存管理单元,通常集成在CPU上)来对虚拟地址进行映射,就可以访问到不同的所需数据,实现了进程的“隔离性”。
注意:如果多个进程同时执行,那虚拟内存的总和大于真实内存怎么办?1.实际上,同时执行的进程一般不会很多。2.即使多个进程同时执行,但是也不是同时把所有虚拟地址空间全部占满。3.极端情况下,出现多个进程都占用了很大的内存,那么就换电脑(内存更大的)。这种情况一般都算bug,需要程序员优化程序,想办法让其占用更少的内存空间。
1.4 进程间通信
只让进程具有“隔离性”并不能满足所有的任务,比如在打微信电话,不仅需要微信程序,还需要摄像程序,这就涉及到进程间的通信。进程间通信包括:管道、共享内存、文件、信号、信号量和网络等方式。其中,网络是一种相对特殊的 IPC 机制,它除了支持同主机两个进程间通信,还支持同一网络内部非同一主机上的进程间进行通信。
2 线程
2.1 线程的必要性
一个CPU有多个核,让一个CPU只执行一个任务,仅使用了一个核,也就是CPU使用率极低,浪费了硬件资源,因此我们希望让CPU同时执行多个任务,也就是并发编程。
多进程可以实现并发编程,但是有些场景会频繁的创建/销毁进程,这就非常消耗时间(分配资源是个耗时的行为),为了提高并发编程的效率,就引入了线程。
2.2 线程
线程:一个执行流,又叫轻量级进程(线程的创建、调度和销毁比进程效率更高),同一个进程包含多个线程,每个线程对应自己的PCB,这里称为TCB(这是操作系统原理的概念,Linux没有TCB,对线程和进程都是用PCB),作用与PCB类似。同一个进程内的多个线程共享同一个进程分配的系统资源。操作系统调度以线程为最小单位。
注意:线程是不是越多越好?由于并发编程往往会利用多线程,多个线程的执行需要多个CPU核心,因此当线程的数量高于CPU核心数,此时再增加线程的数量不会提高任务的执行速度,反而有可能拖累总任务,因为创建销毁线程也需要开销。
2.3 进程和线程的区别
1.进程是系统进行资源分配的最小单位,线程是系统调度的最小单位。
2.进程有自己的内存地址空间,线程只独享指令流执行的必要资源,如寄存器和栈。
3.由于同一进程的各线程间共享内存和文件资源,可以不通过内核进行直接通信。
4.线程的创建、切换及终止效率更高。
5.多个进程同时执行,如果某一个进程出错崩溃,其他进程不受影响。同一个进程的多个线程同时执行,如果某一个线程出错崩溃,很可能导致进程也崩溃,从而导致其中的所有线程都崩溃。