Ch03 - 进程
进程是执行的程序,是操作系统进行资源分配的基本单位。包括:
- 程序代码(文本段/代码段)
- 程序计数器(PC)
- 堆栈(临时数据,如函数参数、返回地址、局部变量)
- 数据段(包括全局变量)
- 堆
进程状态
- 新的new
- 运行running:指令正在执行
- 等待waiting:等待某个事件(如IO完成或者其他信号)
- 就绪ready:等待分配CPU
- 终止terminated
进程控制块PCB
是操作系统内的每个进程表示,包含了许多与某个进程相关的信息。进程之间进行CPU切换时,就要经过保存状态到PCB和从PCB读取状态的过程。
线程
许多现代操作系统扩展了进程概念,以便支持一次能够执行多个线程。此时,PCB被扩展到包括每个线程的信息。
进程调度
进程调度器(Scheduler)选择一个可用进程到CPU上执行。
调度队列
- 作业队列:进程进入系统时先被添加到作业队列
- 就绪队列:就绪的、等待运行的进程
- 设备队列:每个设备都有自己的设备队列,保存等待特定IO设备的进程列表
调度程序
-
长期调度程序 —— 不频繁执行
从进程缓存池中选择进程,加到内存以便执行
-
短期调度程序 —— 快速,频繁执行
从准备执行的进程中选择进程,并分配CPU
-
中期调度程序
某些操作系统引入。可将进程从内存或CPU竞争中移出,从而降低多道程序程度,之后再次调入并从中断处继续执行(换出和换入)
上下文切换
内核将旧进程状态保存在其PCB中,然后加载调度要执行的新进程的上下文
进程运行
进程树:进程在执行过程中可能创建多个新的子进程,这样就形成了进程树
进程标识符PID:进行进程的识别,每个进程有唯一的PID
创建新进程
-
两种执行可能:
- 父进程与子进程并发执行
- 父进程等待,直到某个或全部子进程执行完
-
子进程地址空间两种可能:
- 共享父进程的程序和数据
- 加载另一个新程序
-
流程示意图:
如果不调用exec,子进程就作为父进程的副本执行。
进程终止
- 子进程调用exit来终止
- 父进程可以通过系统调用wait来等待子进程的终止
- 当一个进程终止时,操作系统会释放其资源,但它位于进程表中的条目还是在的,直到它的父进程调用wait
- 当进程已经终止,但父进程尚未调用wait,就成为僵尸进程。这种状态一般都会短暂存在
- 如果父进程没有调用wait就终止,子进程就成为孤儿进程。Linux和UNIX的解决方法是使用根进程init作为孤儿进程的父进程,定期调用wait。
进程间通信(IPC)
共享内存系统
用基于生产者-消费者模型的共享内存进行通信。缓冲区可以是有界缓冲区(有限大,生产者不用等待)和无界缓冲区(无限大,生产者消费者都可能等待)。
消息传递系统
问题1 - 直接 / 间接
-
直接通信
需要通信的进程必须明确指定通信的接收者或发送者
send(P, msg); receive(Q, msg); // [对称] P、Q是相应的进程 send(P, msg); receive(id, msg); // [非对称] 从任何进程receive msg
-
间接通信
通过邮箱机制。
- 只有两个进程共享一个邮箱时才能建立通信链路;
- 一个链路可以和两个或更多进程关联;
- 两个进程直接可有多个不同链路,每个链路对应一个邮箱;
- 根据具体实现,邮箱可以由进程持有,也可以由操作系统持有。
send(A, msg); receive(A, msg);
问题2 - 同步 / 异步
下面称同步为阻塞的,异步为非阻塞的。
- 阻塞发送:等,直到对方收到
- 非阻塞发送:不等,发了就恢复自己的操作
- 阻塞接收:等,直到收到数据
- 非阻塞接收:不等,来了再去处理
问题3 - 缓冲
无缓冲的消息系统:缓冲队列零容量
自动缓冲的消息系统:缓冲队列有限或无限容量
客户机 / 服务器通信
-
套接字Socket
面向连接的TCP、无连接的UDP。套接字只能在通信线程之间交换无结构的字节流。
-
远程过程调用RPC
消息有明确的结构。模拟了典型的子程序过程调用,而且能在系统之间工作。可用于实现分布式文件系统。
-
管道Pipe
-
普通管道
单向的。两个进程按生产者-消费者方式进行通信。
-
命名管道
可以是双向的,父子关系不是必须的,多个进程都可用它通信。
-