操作系统-进程方案
进程的概念
进程调度
操作进程
进程间通信
系统的例子IPC
客户机-服务器系统中的通信
操作系统-进程方案
目标
介绍进程的概念——一个正在执行的程序,它构成了所有计算的基础
描述过程的各种特性,包括调度、创建和终止,以及通信
描述客户机-服务器系统中的通信
进程的概念
操作系统执行各种各样的程序:
批处理系统-作业
分时系统——用户程序或任务
我们几乎可以交替使用作业和加工这两个术语
进程——一个正在执行的程序;流程执行必须按顺序进行
这一过程包括:
程序计数器(下一条要执行指令的地址)
堆栈
数据部分
进程的内存
text data heap stack
进程的状态
当进程执行时,它会改变状态
new:正在创建进程
running:正在执行指令
waiting:进程正在等待某个事件发生
ready好:进程正在等待分配给处理器
terminated:进程已经完成执行
进程的状态图
new一个进程 => ready(准备阶段 => running(运行阶段) =>
如果运行完成 => exit(退出程序)
如果超时或者其它原因 cpu被系统收回 => 就到ready阶段
如果是调用了休眠等状态 => 就到waiting(等待接触)的状态 => ready(准备阶段)
过程控制块(PCB)
与每个进程相关联的信息
流程状态
程序计数器
CPU寄存器
CPU调度信息
内存管理信息
会计信息
I / O状态信息
进程调度
cpu调度进程
process状态 process进程号 process计数器 寄存器 内存 ..
进程调度队列
作业队列-系统中所有进程的集合
就绪队列——驻留在主存中的所有进程的集合,准备好并等待执行
设备队列—等待I/O设备的进程集
进程在不同的队列之间迁移
进程在执行时 os可以中断,然后保存信息到pcb,再次运行时,通过PCB读取出中断时的状态
准备好的队列,进入cpu执行,遇到io则去执行io,cpu执行下一个程序,
当遇到 io 时间到 出现子程序 等待interrupt 会将cup拉回,
调度者
长期调度器(或作业调度器)——选择应该将哪些进程引入就绪队列
短期调度器(或CPU调度器)——选择下一个应该执行的进程并分配CPU
长期调用队列进入 短期执行完毕释放cup 遇到io执行io然后重到队列 需要交互则返回进行交互,完成之后回到队列,等待cpu的调用.
调度器
短期调度器调用非常频繁(毫秒)(必须快)
调用长期调度器的频率非常低(秒、分钟)(可能很慢)
长期调度器控制多道编程的程度
过程可以描述为:
I/O绑定进程——花费更多的时间进行I/O操作,而不是进行计算,导致大量的CPU突发
cpu绑定进程——花费更多的时间做计算;很少长时间的CPU突发
上下文转换
当CPU切换到另一个进程时,系统必须保存旧进程的状态,并通过上下文切换为新进程加载保存的状态
PCB中表示的流程的上下文
上下文切换时间是开销;系统在切换时没有任何有用的工作
时间取决于硬件支持
操作进程
进程创建
父进程创建子进程,子进程又创建其他进程,形成一个进程树
通常,通过进程标识符(pid)识别和管理进程。
资源共享
父母和孩子共享所有资源
子节点共享父节点资源的子集
父类和子类不共享资源
执行
父节点和子节点并发执行
父母会等到孩子终止
地址空间
父副本的子副本
Child里面装了一个程序
UNIX的例子
fork系统调用创建新的进程
在fork之后使用exec系统调用,用一个新程序替换进程的内存空间
parent wait child完成 后 parent再来执行
进程终止
进程执行最后一条语句,并请求操作系统删除它(退出)
从子节点到父节点的输出数据(通过等待)
进程资源被OS重新分配
父进程可以终止子进程的执行(abort)
子节点超过了分配的资源
分配给child的任务不再需要
如果父进程退出
一些操作系统不允许父进程终止时子进程继续
所有子代终止-级联终止
系统中的过程可以是独立的,也可以是协作的
独立进程不能影响或被另一个进程的执行所影响
协作过程可能影响或被其他过程影响,包括共享数据
合作过程的原因:
信息共享
计算加速
模块化
方便
协作的进程需要进程间通信(IPC)
IPC的两种模式
共享内存
消息传递
通信模型
独立进程 process A 进入kernel执行,当执行Process B时,将Process A全部拿出.
交互进程 在process A 和 process B之间有一个shared区域,process A 和B 可以在这里进行数据交互
生产者消费者问题
作为协作过程的范例,生产者过程产生的信息被消费者过程消费
unbounded-buffer对缓冲区的大小没有实际限制
bound -buffer假设缓冲区大小是固定的
绑定缓冲区共享内存解决方案
Shared data
define BUFFER_SIZE 10
typedef struct {
. . .
} item;
item buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
解决方案是正确的,但只能使用BUFFER_SIZE-1元素
有界限的缓冲区,生产商
while (true) { / Produce an item /
while (((in = (in + 1) % BUFFER SIZE count) == out)
; / do nothing -- no free buffers /
buffer[in] = item;
in = (in + 1) % BUFFER SIZE;
}
有界缓冲区消费者
while (true) {
while (in == out)
; // do nothing -- nothing to consume
// remove an item from the buffer
item = buffer[out];
out = (out + 1) % BUFFER SIZE;
return item;
}
进程间通信
用于进程通信和同步其操作的机制
消息系统——进程之间进行通信而不借助于共享变量
IPC设施提供两种操作:
发送(消息)-消息大小固定或可变
接收(消息)
如果P和Q希望沟通,他们需要:
在他们之间建立沟通联系
通过发送/接收交换消息
通信链路的实现
物理(例如,共享内存,硬件总线)
逻辑的(例如,逻辑属性)
实现问题
如何建立联系?
一个链接可以与两个以上的进程相关联吗?
在每一对通信进程之间可以有多少个链接?
链路的容量是多少?
链接可以容纳的消息大小是固定的还是可变的?
链接是单向的还是双向的?
直接通讯
进程必须显式地彼此命名:
发送(P,消息)-发送一个消息给进程P
接收(Q,消息)——从进程Q接收一条消息
通信链路的特性
链接自动建立
一个链接只与一对通信进程相关联
每一对之间只存在一个链接
链接可能是单向的,但通常是双向的
间接沟通
从邮箱(也称为端口)定向和接收消息
每个邮箱都有一个唯一的id
进程只有在共享邮箱时才能通信
通信链路的特性
仅当进程共享一个公共邮箱时才建立链接
一个链接可能与许多进程相关联
每一对进程可以共享几个通信链路
链接可以是单向的,也可以是双向的
操作
创建一个新邮箱
通过邮箱发送和接收消息
摧毁一个邮箱
原语的定义如下:
发送(A,消息)-发送消息到邮箱A
接收(A,消息)——从邮箱A接收一条消息
邮箱共享
P1、P2、P3共享邮箱A
P1,发送;P2和P3接收
谁会得到这个信息?
解决方案
允许一个链接最多与两个进程相关联
一次只允许一个进程执行接收操作
允许系统任意选择接收机。发送方被通知收件人是谁。
同步
消息传递可以是阻塞的,也可以是非阻塞的
阻塞被认为是同步的。
阻塞发送使发送方阻塞,直到收到消息
阻塞接收将阻塞接收方,直到有消息可用为止
非阻塞被视为异步的
非阻塞发送让发送者发送消息并继续
非阻塞接收让接收方接收到有效的消息或为空
缓冲
连接到该链接的消息队列;以三种方式之一实现
- 零容量- 0条消息
发送方必须等待接收方(会合)
- 有限容量—n条消息的长度有限
如果链接已满,发送者必须等待
- 无限容量-无限长度
发送者从不等待
系统的例子IPC
POSIX共享内存
进程首先创建共享内存段
segment id = shmget(IPC PRIVATE, size, S IRUSR | S iusr); / /删除所有iusr
想要访问该共享内存的进程必须附加到它
共享内存= (char *) shmat(id, NULL, 0);
现在进程可以写入共享内存了
sprintf(共享内存,写入共享内存);
完成后,进程可以将共享内存与其地址空间分离
shmdt(共享内存);
说明POSIX共享内存API的C程序
Mach通信是基于消息的
甚至系统调用也是消息
每个任务在创建时都有两个邮箱——Kernel和Notify
消息传递只需要三个系统调用
msg_rpc msg_receive msg_send () () ()
通信所需的邮箱,通过
port_allocate ()
IPC系统的例子- Windows XP
以本地过程调用(LPC)工具为中心的消息传递
仅在同一系统上的进程之间有效
使用端口(如邮箱)建立和维护通信通道
沟通工作如下:
客户端打开子系统的连接端口对象的句柄
客户端发送连接请求
服务器创建两个私有通信端口,并将其中一个端口的句柄返回给客户机
客户机和服务器使用相应的端口句柄发送消息或回调,并侦听响应
Windows XP中的本地过程调用
客户机-服务器系统中的通信
套接字
套接字被定义为通信的端点
IP地址和端口的连接
socket 161.25.19.8:1625指主机161.25.19.8上的端口1625
通信由一对套接字组成
套接字通信
Java提供了三种不同类型的套接字。
面向连接(TCP)套接字是用socket类实现的。
无连接(UDP)套接字使用DatagramSocket类。
MulticastSocket类是DatagramSocket类的子类。多播套接字允许数据发送到多个接收者。
示例:数据服务器使用面向连接的TCP套接字。
允许客户端向服务器请求当前日期和时间。
远程过程调用
远程过程调用(Remote procedure call, RPC)抽象了网络系统进程之间的过程调用
存根——服务器上实际过程的客户端代{过}{滤}理
客户端存根定位服务器并编组参数
服务器端存根接收此消息,解包编组的参数,并在服务器上执行该过程
管道允许两个进程通信。
早期UNIX中最早的IPC机制之一。
实现管道必须考虑四个问题:
单向通信还是双向通信?
如果是双向,半双工还是全双工?
通信进程之间必须存在一种关系(如父-子)吗?
管道是否可以通过网络进行通信,或者只是驻留在同一台机器上?
两种类型的管道
普通的管道
普通管道允许两个过程以生产者-消费者的方式进行通信。
生产者写管道的一端(写端),消费者读管道的另一端(读端)。
这是单向的
在UNIX系统上,普通管道是使用
管(int fd [])
fd[]:文件描述符,fd[0]:管道的读端
Fd[1]:管道的写端
UNIX将管道视为一种特殊类型的文件。可以使用read()和write()系统调用访问管道。
普通管道不能从创建它的进程外部访问。
父进程创建一个管道,并使用它与它通过fork()创建的子进程通信。
子进程从父进程继承打开的文件(也称为管道)。
unix的管道
windows的匿名管道
Windows系统中的普通管道称为匿名管道。
单向,利用亲子关系。
win32 API创建管道
CreatePipe ()
ReadFile()和WriteFile()用于读和写
CreatePipe()的四个参数
单独的读写手柄
一个STARTUPINFO结构实例(指定子进程要继承管道的句柄)
管道大小(以字节为单位)
命名管道
普通管道仅在进程之间进行通信时存在。
在UNIX和Windows系统上,一旦进程完成通信并终止,普通管道就不再存在。
命名管道提供了双向通信,并且没有父子关系。
一旦建立了命名管道,多个进程就可以使用它进行通信。因此,一个命名管道可能有几个写入器。
命名管道在通信进程完成后继续存在。
在UNIX中,命名管道称为fifo。
一旦创建,它们就会作为文件系统中的典型文件出现。
使用mkfifo()系统调用创建FIFO,并使用open()、read()、write()和close()系统调用操作FIFO。
fifo是双向的,具有半双工传输。但是只能传输面向字节的数据。
通信进程必须在同一台机器上。如果需要机器间通信,必须使用套接字。
Windows系统上的命名管道提供了更丰富的通信机制。
允许全双工通信,并且通信的进程可能驻留在不同的机器上。
可以传输面向字节或消息的数据。
命名管道是用CreateNamePipe()函数创建的,客户端可以使用ConnectNamePipe()连接到管道。
通过命名管道通信:ReadFile()和WriteFile()函数。
管道的应用
在UNIX命令行环境中,管道是非常开放的。
在ls和more命令(作为单独的进程运行)之间设置管道,允许将ls的输出作为more的输入传递。
可以使用" | "字符在命令行上构造管道。
ls |more 一屏幕一屏幕的展示信息
Windows系统
dir |more 一屏幕一屏幕的展示信息
客户机-服务器系统中的通信