操作系统(三) 进程
早期计算机系统只允许一次执行一个程序。这种程序对系统有完全的控制,能访问所有的系统资源。线代计算机系统允许将多个程序调入内存并发执行,这要求对各种程序提供更加严格的控制和更好的划分。
这些需求产生了进程的概念,即执行中的程序。
操作系统关注执行用户程序,需要照顾各种系统任务。因此系统由一组进程组成:操作系统进程执行系统代码,用户进程执行用户代码。通过(多个)CPU在进程之间的切换(多路复用),所有这些进程都有可能并发执行,从而操作系统能使计算机更高效。
先简单区分下进程和线程:
进程是现代分时系统的工作单元;
A process, in the simplest terms, is an executing program
A “process” is what we call a program that has been loaded into memory along with all the resources it needs to operate。Some essential resources every process needs are registers, a program counter, and a stack.
线程是CPU使用的基本单元;
A thread is the unit of execution within a process.
A thread is the basic unit to which the operating system allocates processor time. A thread can execute any part of the process code, including parts currently being executed by another thread.
一、进程的概念
在讨论操作系统时,把CPU上的各种活动统称为进程。
1、进程
进程是执行中的程序,这是一种非正式的说法。
进程不只是程序代码,程序代码称为文本段。进程还包括当前活动,通过程序计数器的值和处理器寄存器额内容表示。此外,进程通常还包括进程堆栈段(包含零食数据,如方法参数、返回地址和局部变量)和数据段(包含全局变量)。
程序本身不是进程,程序是被动实体,进程是活动实体,它有一个程序计数器来表示下一个要执行的指令和相关资源集合。
两个进程可能与同一个程序相关,但是他们被当作两个独立的执行序列。例如我打开两个word文档,这两个独立的进程虽然文本段相同,但是数据段不同。
程序计数器(Program Counter (PC)),是在电脑处理器中的一个寄存器,用来指示电脑下一步要运行的指令序列。
寄存器(Register),是中央处理器内的其中组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。在中央处理器的控制部件中,包含的寄存器有指令寄存器(IR)和程序计数器。在中央处理器的算术及逻辑部件中,包含的寄存器有累加器。
2、进程状态
任何时刻一次只能有一个进程在任何一个处理器上运行。
3、进程控制块(PCB)
每个进程在操作系统内用进程控制块来表示,一个PCB包含与特定进程相关的许多信息。
CPU在进程间进行切换时,被中断的进程当时的信息会保存进PCB,之后这个进程又执行时,会从同一个PCB中获取相关信息。
二、进程调度
1、调度队列
进程进入系统时,被加到作业队列(Job Queue),该队列包括系统中所有的进程。
驻留在内存中就绪的等待运行的进程保存在就绪队列表上,该队列通常用链表形式来存储,其头结点包括指向链表的第一个和最后一个PCB块的指针。可以为每个PCB增加一个指针域来指向就绪队列的下一个PCB。
进程执行后,可能会请求I/O。等待特定I/O设备的进程列表称为设备队列,每个设备都有自己的设备队列。
新进程开始处于就绪队列,它在就绪队列中等待直到被选中执行(或分派),当进程分配到CPU并执行时,有下列情况会发生:
- 进程可能会发出一个I/O请求,并被放到I/O队列中;
- 进程可能创建一个新的子进程,并等待其结束;
- 进程可能会由于中断而被强制移出CPU,并被放回到就绪队列
2、调度程序(scheduler)
进程在其生命周期中会在各种调度队列之间迁移,OS会按某种方式从这些队列中选择进程。进行这种选择的是相应的调度程序来完成。
两种调度程序:
作业调度程序(长期)从磁盘上的缓冲池中选择进程,将他们装入内存;
CPU调度程序从内存中的就绪可执行的进程中选择进程,并为其中之一分配CPU。
长期调度程序对进程的筛选:合理地选择一个I/O为主进程和CPU为主的进程的进程组合。
有的操作系统如分时系统,可能引入中等程度的调度程序。中期调度程序能将进程移出内存。之后,进程可被再次调入内存,从中断处继续执行。
3、上下文切换
Context Switch:将CPU切换到另一个进程需要保存原来进程的状态并装入新进程的保存状态。(进程的关联状态由PCB保存)
三、进程操作
进程创建:
进程在其执行过程中,能创建新的进程。于是有了父进程和子进程的概念,子进程也可以再创建新的进程,形成进程树。
当父进程创建新进程时,有两种执行可能:
(1) 父进程与子进程并发执行;
(2) 父进程等待,直到某个或者全部子进程全部执行完毕。
新进程的地址空间也有两种可能:
(1) 子进程是父进程的复制品;
(2) 子进程装入另一个程序进来;
进程终止:
进程被终止时,所有的进程资源,包括物理和虚拟内存、打开文件和I/O缓冲,会被OS释放。
父进程通过适当的系统调用能终止另一个进程,所以父进程需要知道子进程的标识符。在父进程创建一个新进程时,新进程的标识符要传递给父进程。
父进程终止子进程的原因:
- 子进程使用了超过它所分配到的一些资源。这要求父进程有一个检查其子进程的状态的机制;
- 分配给子进程的任务已不再需要;
- 父进程退出,如果父进程终止,OS不会允许子进程继续。这叫级联终止。
四、进程协作
如果一个进程不能影响或被在系统内执行的其他进程所影响,那么该进程是独立的不与其他进程共享任何数据的进程是独立的;
相反,则该进程是协作的。与其他进程共享数据的进程是协作进程。
显然协作进程是被需求的,协作进程的并发执行要求一定的机制,允许进程间相互通信和同步动作。
生产者消费者问题——进程协作的通用范例
生产者和消费者之间有一个缓冲区,它被生产者填充,被消费者消耗。它可以是有限的(实际讨论价值)和无限的。
缓冲区可以由OS通过使用进程间通信(IPC)功能 or 由应用程序员通过使用共享内存来显示编码。
例如共享内存方案,共享缓冲可以通过循环数组和两个逻辑指针in和out来实现。in指向缓冲区的下一个空位;out指向缓冲区第一个非空位。当in==out,缓冲区为空;当(in+1)%BUFFER_SIZE时,缓冲区为满。这种方案最多允许缓冲区同时有 BUFFER_SIZE-1个项。
五、进程间通信
这里讨论由OS提供IPC功能进行进程间的通信。
IPC在分布式环境中作用很大,因为通信的进程可能位于由网络连接起来的不同计算机上,如QQ。
1、消息传递
IPC(InterProcess Communication)的实现可以通过消息传递完成,这样IPC工具至少提供两个操作:发送消息和接收消息。
如果进程P和Q需要通信,那么他们必须相互发送消息和接收消息;他们之间必须要有通信线路。我们关心的是通信线路的逻辑实现,而非物理。
2、命名
需要通信的进程必须要有一个方法相互引用,他们可以使用直接或间接通信。
(1) 直接通信
通信的进程必须明确地命名通信的接收者或发送者。
(2) 间接通信
消息通过邮箱或端口来发送和接收。
端口被抽象成一个对象,进程可以向其中存放消息也可以从中删除消息。每个端口都有一个唯一的标识符。
这种方案中,一个进程可以通过不同的端口与其他进程进行通信。如果两个进程共享一个邮箱,那么他们可以进行通信。
六、客户机-服务器系统通信
1、套接字(Socket)
Socket可以理解为通信的端点,一对通过网络进行通信的进程需要一对套接字。
套接字由IP地址和端口号组成,在客户机-服务器系统中,服务器通过监听指定端口等待客户请求。收到请求后,建立与客户套接字的连接,进行通信。
所有端口号低于1024的端口都认为是众所周知的,可以用来实现标准服务。
2、Java中的Socket
Java提供了三种不同类型的套接字:
- 面向连接(TCP)套接字用Socket类实现;
- 无连接(UDP)套接字使用DatagramSocket类;
- MuticastSocket类是DatagramSocket类的子类,允许数据发送给多个接收者。
使用套接字通信,虽然普遍和高效,但是它属于底层形式的分布式进程通信。一个理由是,套接字只允许在通信进程间交换无结构的字节流,客户机或服务器需要负责加上数据的结构。
3、RPC和RMI
高层的通信方法有:远程过程调用(RPC)和远程方法调用(RMI)。
二者的区别是,RPC传递给远程进程的数据是按普通数据结构形式的,RMI允许在远程方法调用中传递对象。
RMI是RPC的Java版,它允许线程如同调用本地对象的方法一样来调用远程对象的方法。