进程,是指运行中的程序,也称为作业。
早期的计算机,只允许运行 一个
程序,这个程序被分配了计算机所能提供的所有资源。
现代的计算机,允许并行运行 多个
程序,系统资源也就被这些程序瓜分。
每一个程序也就成为了一个 工作单元
,将这些 工作单元
称呼为:进程
。
因此,进程
也是计算机系统分配资源
的基本单位。
程序,是静态的代码,而进程是动态的实体。
程序,也就是 代码
,在硬盘中存放着,经过 主存储器(内存)
的加载,被封装成 PCB
数据结构,在 内核队列
中排队,等待 CPU调用
执行。相同的一份代码,可以被多次加载,形成多个独立的进程,对于系统来说,不过是队列中多了一个成员,当然,资源也是需要被瓜分的。
操作系统通过进程控制块PCB来表示进程。
进程控制块
,也就是PCB,是操作系统内部的一种用来表示进程
的数据结构
,记载着和进程相关的一些信息。
包括:内存指针、进程状态、进程号、程序计数器、寄存器、内存限制说明、I/O状态信息等。
内存指针
,进程内存数据相关的指针。进程状态
,包含:新建、就绪、运行、阻塞、停止。进程号
,用来标识唯一进程的标识符,也就是PID。程序计数器
,用来标识程序要执行的下一条指令的地址。寄存器
,用于发生CPU中断时临时存储信息。内存限制说明
,包含了内存管理系统的一些信息,比如:页表、段表。I/O状态信息
,包含了进程打开的文件列表及分配给进程的I/O设备。
进程的一生都在队列之间徘徊,一旦被CPU调用,那么就出队列,改变状态,读取PCB中记录的信息,恢复现场(也就是CPU上下文切换
),相同状态的PCB会形成链表,从程序计数器记录的地址开始执行,直到时间片用完或者被中断,回到队列之中或者执行结束,释放资源。
如果,所有的进程都是CPU繁忙型
,那么等待队列
(CPU都在忙着)几乎都是空的。
如果,所有的进程都是I/O繁忙型
,那么就绪队列
(CPU都在闲着)几乎都是空的。
那么,就需要合理分配进程组合,避免内存需求过多或者设备过度空闲。
一个进程,在运行期间可以创建多个子进程。
创建进程的进程称为父进程
,通过fork
来实现,而子进程
也可以再创建子进程,形成一个进程树
。
创建进程是需要分配系统资源的,子进程所需要的资源可以直接
从系统获取,也可以从父进程获取,父进程所拥有的数据也可以传送
给子进程,父子进程也可以共享
同样的资源。
子进程也不是无限制的创建的,需要受限
于父进程,否则会负载过高。
进程之间,可以通过多种方式相互通信。
进程的通信可以分为:直接通信、间接通信。
具体的方式包含:管道、信号、消息队列、Socket、共享内存。
管道
,一种半双工的通信方式,数据只能在父子进程之间单向流动。信号
,一种异步通信方式,通过监听、中断来实现,如:SIGINT。消息队列
,是一种保存在内核中的消息的链表,进程之间通过读写消息队列通信。Socket
,通过TCP、UDP协议进行通信。共享内存
,多个进程读取同一块共享的内存。
最后,进程是系统分配资源的基本单位,是执行中的程序,被封装为PCB数据结构,由CPU来进行调度,每次调度将会加载进程数据,切换上下文,通过此方式切换进程,成本也是过高。
因此,诞生了线程
。
线程,本质上是轻量级进程,且共享了进程所拥有的数据和资源。
线程,建立在进程的基础上,一个进程可以拥有多个
线程,每一个线程共享
进程的数据和资源,并且可以拥有自己独享
的数据,是CPU执行的基本单位
。通过线程这种方式,CPU无需进行复杂的进程上下文切换
,只需要切换线程即可,内存数据在同一个进程内是共享的,相比切换进程来说,成本明显降低许多。
一个线程,包含:代码、数据、打开文件列表、寄存区、程序计数器、堆栈。
多个线程之间,处于并行状态。
举例,在我们打开浏览器的时候,一个线程负责拉取数据,一个线程负责加载页面,一个线程负责显示图像等,这几个线程之间互不影响,换做进程的话,需要来回切换。
在RPC
的场景中,每来一个请求,就单独使用一个线程来处理,比起单线程来说,并行
的方式显然提高了处理的效率。当然,线程也不是无限开辟的,可创建的线程数受限于所拥有的资源。虽然创建线程的成本比创建进程的成本低,但也不是没有成本的。为了降低这种成本,基于线程池
,可以快速创建进程,充分利用资源。
线程的实现方式有:一对一、多对一、多对多。
线程分为用户线程
、内核线程
,用户线程由内核线程来实现。
一对一模型
情况下,一个用户线程由一个内核线程来实现。这种方式使得线程之间并行化,不会因为一个用户线程的阻塞导致其它用户线程的阻塞,但是资源消耗就比较大了。
多对一模型
情况下,将多个用户线程映射到一个内核线程。这种方式使得线程管理变得方便了,但一次只能执行一个线程,无法并行化,如果一个用户线程阻塞,将导致所有由此内核线程实现的用户线程阻塞。
多对多模型
情况下,多个用户线程映射到多个内核线程上,处于交叉状态,做到多路复用,一个内核线程阻塞的情况下,可以切换到其它的内核线程,避免了上面两种模型的缺点。