操作系统--进程操作(五)

4.4 进程协作

执行在操作系统内的并发进程可以是独立进程或协作进程。 如果一个进程不能影响或被在系统内执行的其他进程所影响, 那么该进程是独立的。显然, 不与其他任何进程共享数据(临时或永久)的进程 是独立的。另一方面, 如果一个进程能影响或被在系统内执行的其他进程所影响,那么该进程是协作的。显然,与其他进程共享数据的进程是协作进程。

人可能需要提供环境以允许进程协作,这有许多理由:

  • 信息共享(information sharing):由于多个用户可能对同样的信息感兴趣(例如, 共享文件),所以必须提供环境以允许这些类型资源的并发访问。
  • 加快计算(computation speedup):如果希望一个特定任务快速运行,那么必须将它分成子任务,每个子任务可以与其他子任务并行执行。如果计算机有多个处理单元(例如, CPU或I/O通道),才可实现这样的加速。
  • 模块化(modularity):可能需要按照模块化方式构造系统,如第三章所讨论的,可将系统功能划分成独立进程或线程。
  • 方便(convenience):单个用户也可能同时执行许多任务。 例如,一个用户可能编辑、打印和并行编辑。
    协作进程的并发执行要求一定机制,以允许进程间互相通信和同步动作。
    为了说明协作进程这一概念,现在来研究一下生产者-消费者 问题, 这时协作进程的通用范例。
    生产者进程生产消息,以供消费者进程消费。例如,打印程序生产字符,以供打印机驱动程序所使用。编辑器生产的汇编代码供汇编程序使用;汇编程序产生目标模块供装入程序使用。
    为了允许生产者进程和消费者进程能并发执行,必须要有一个目标缓冲区来被生产者填充并被消费者 所使用。 当消费者使用一项时, 生产者能生产一项。 生产者和消费者必须是同步的,这样消费者就不会试图使用一个没有生产出来的项。这种情况下, 消费者必须等待一项被生产出来。
    无限缓冲(unbounded-buffer)生产者-消费者问题对缓冲区大小没有实际限制。虽然消费者可能需要等待新项目,但是生产者总是在产生新项。 有限缓冲生产者-消费者问题假设缓冲区大小固定。 对于这种情况,如果缓冲区为空,那么消费者必须等待;如果缓冲区为满,那么生产者必须等待。

缓冲区可以由操作系统通过使用 进程间通信(interprocess-communication IPC)功能或由应用程序员通过使用共享内存来显示编码。下面给出有限缓冲问题的共享内存解决方案。生产者进程和消费者进程共享如下变量:

define BUFFER_SIZE 10
typedef struct{
...
} item;
item buffer[BUFFER_SIZE];
int in = 0;
int out = 0;

共享缓冲区是通过循环数组和两个逻辑指针来实现的: in 和 out 。变量in 指向缓冲区中下一个空位; out指向缓冲区 中的第一个非空位。 当in == out 时, 缓冲区为空; 当 (in + 1)%BUFFER_SIZE ==out 时, 缓冲区为满。
生产者进程和消费者进程代码如下。 生产者进程有一个局部变量nextProduced,以 存储所生产的新项:

while(1){
/*produce an item in nextProduced*/
while(((in + 1) % BUFFER_SIZE) == out)
; /*do nothing*/
buffer[in] = nextProduced;
in = (in + 1)% BUFFER_SIZE;
}
消费者进程有一个局部变量nextConsumed,以存储所有要使用的项:
while(1){
	while(in == out)
	; // do nothing
	nextConsumed = buffer[out];
	out = (out +1)% BUFFER_SIZE;
	/*consume the item in nextConsumed*/
}

这种方案最多允许缓冲区同时中有BUFFER_SIZE - 1一个项。 关于缓冲区同时能存储 BUFFER_SIZE个项的解决方法,可以想一下。以后会讨论。

4.5 进程间通信

上一节讨论了协作进程如何能通过共享内存环境来通信。这种方法要求进程共享同一个缓冲池,并且实现缓冲的代码需要应用程序员自己明确编写。 实现这种效果的另一种方法是操作系统提供机制,让协作进程能通过进程间通信(IPC)工具来进行彼此间的通信。

IPC提供一种机制,以允许进程不必通过共同地址空间 共享来通信和同步其 动作。 IPC在分布式环境中(通信 进程可能位于由网络连接起来的不同计算机上)尤其有用。 在万维网使用的chat 程序就是一个例子。

IPC最好由消息传递系统提供,消息系统由许多定义方式。 本节讨论消息传递系统设计的不同问题。

4.5.1 消息传递系统

消息系统的功能是允许进程互相 通信而不需要利用共享数据。 大家已经知道消息传递作为微内核中的通信放方式。这种方案中,服务是通过普通用户进程提供的,即服务在微内核之外进行。用户进程间的通信是通过消息传递完成的。IPC 工具至少提供两个操作: 发送消息和接收消息。

由进程发送的消息可以是定长的或变长的。如果只能 发送定长消息,那么系统级的实现是简单的。不过,这一限制使得编程任务更加困难。另一方面,变长消息要求更复杂的系统级实现,但是编程任务变得更为简单。

如果进程P和Q 需要通信,那么它们必须互相发送消息和接收消息; 它们之间必须要有 通信线程(communication link)。该线路有多种实现方法。 这里并不关心线路的物理实现(如共享内存、硬件总线或网络),而只关心其逻辑实现。如下是一些逻辑实现线路和 返送/ 接收操作的方法:

  • 直接或间接通信
  • 对称或非对称通信
  • 自动或显示缓冲;
  • 复制发送或应用发送;
  • 固定大小或可变大小消息。

下面研究这些类型的消息系统。

4.5.2 命名

需要通信的进程必须有一个方法一互相引用。它们可使用直接或间接通信。

1、直接通信

对于 直接通信, 需要通信的进程必须明确地命名通信的接受者或发送者。采用这种方案,原语 send 和 receive定义如下:

  • send (P, message),发送消息到进程P。
  • receive(Q, message),接收来自进程Q的消息。

方案的通信线程具有如下属性:

  • 在需要通信的一对进程之间,自动建立线路,进程只需知道彼此的标识,以便进行通信。
  • 一个线路只与两个进程相关。
  • 每对进程之间只有一个线路。

这种方案展示了对称寻址,即发送进程和接收进程必须命名对方,以便通信。这种方案的一个变形采用非对称寻址。只要发送者命名接受者,而接收者不需要命名发送者。采用这种方案,源于 send 和 receive定义如下:

  • send(P, message) :发送消息到进程P
  • receive(id, message):接收来自任何进程的消息,变量id设置成与其通信的进程名称。
    对称和非对称寻址方案的共同缺点 是限制了结果进程定义的模块化。改变进程的名称可能必须检查所有其他进程定义。所有旧名称的引用都必须被找到,以便修改成为新名称。 这种情况从独立编译角度来说是不可取的。

2. 间接通信

对于间接通信,消息通过 邮箱或端口 来发送和接收。 邮箱可以被抽象成一个对象,进程可以向其中存放消息 也可从中 删除消息。 每个邮箱都有一个唯一的标识符。 对于这种方案,一个进程能通过不同的邮箱与其他进程进行通信。 如果两个进程共享一个邮箱,那么它们可以进行通信。原语 send 和 receive定义如下:

  • send(A, message): 发送一个消息到邮箱A。
  • receive(A, message):接收来自邮箱A的消息。

对于这种方案, 通信线路具有如下属性:

  • 只要一对进程中的两个成员共享一个邮箱,那么就建立了它们之间的通信线程。
  • 一个线路可以与两个或更多的进程相关联。
  • 两个通信进程之间可有多个不同的线路,每个线路对应于一个邮箱。
    现在假设进程P1、P2和P3 都共享邮箱A。进程P1 发送一个消息到 A, 而进程P2 和P3都对 A执行 receive。哪个进程能收到 P1 所发的消息呢? 答案取决于人们所选择的方案:
  • 允许一个线路最多只能与两个进程相关联。
  • 允许一次最多一个进程执行receive操作。
  • 允许系统随意选择一个进程以接收消息(即P1 或P2,而非两者,将接收消息)。系统可以告诉发送者谁是接受者。
    邮箱可以为进程或操作系统所拥有。 如果邮箱为进程所有(即邮箱是进程地址空间的一部分),那么要区分拥有者(能通过邮箱接收消息)和使用者(只能向邮箱发送消息)。 由于每个邮箱都有唯一的拥有者,所以关于谁能就收发到邮箱的消息是没有身混淆的。 当拥有邮箱的进程终止,那么邮箱消失。任何进程后来向该邮箱发送消息,都会得知邮箱不在存在。

另一方面, 由操作系统所拥有的邮箱是独立的。并不属于任何特定的进程。因此,操作系统必须提供机制,以允许进程进行如下操作:

  • 创建一个新邮箱
  • 通过邮箱发送和接收消息。
  • 删除一个邮箱
    创建一个新邮箱的进程缺省(默认)为邮箱的拥有者。开始时, 拥有者是唯一能通过该邮箱接收消息的进程。不过,通过适当的系统调用,拥有权和接收特权可能传递给其他进程。当然,该规定可能会导致每个邮箱拥有多个接受者。

4.5.3 同步

不管通信是直接的或是间接的,通信进程所交换的消息都驻留在临时队列中。简单来说队列实现由三种方法:

  • 零容忍: 队列的最大长度为0; 因此,线路中不能有任何消息处于等待。 对于这种情况,发送者必须阻塞,直到接收者接收到消息。
  • 有限容量: 队列的长度为有限的n;因此,最多只能有n个消息驻留其中。 如果在发送新消息是队列未满,那么 该消息要放在队列中(或者复制消息或者保存消息的指针),且发送者可继续执行而不必等待。不过,线路只有有限容量。如果线路满,发送者必须阻塞直到队列中的空间可用为止。
  • 无限容量: 队列长度可以无限:因此,不管多少消息都可在其中等待, 发送者从不阻塞。
    零容量情况称为没有缓冲的消息系统;其他情况称为自动缓冲。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值