DJ2-6 进程通信

目录

2.6.1  进程的通信类型

1. 共享存储器系统

2. 消息传递系统

3. 管道通信

2.6.2  消息传递系统的实现方法

1. 直接通信方式

2. 间接/信箱通信方式

2.6.3  消息传递系统中的几个问题

1. 消息的格式

2. 进程的同步方式

2.6.4  消息缓冲队列通信机制

1. 数据结构

2. 发送原语

3. 接收原语

plus. 练习


进程通信是指进程之间的信息交换。

1. 低级通信,以信号量机制为例

1)效率低,生产者每次只能向缓冲池投放一个消息,消费者每次只能从缓冲区中取得一个消息。

2)通信对用户不透明,OS 只为进程之间的通信提供了共享存储器,而其它的都必须由程序员自己去实现。

2. 高级通信

是指直接利用 OS 所提供的一组通信命令,高效地传送大量数据的一种通信方式。

1)效率高,用户可直接利用高级通信命令(原语)高效地传送大量的数据。

2)通信实现细节对用户透明,大大减少了通信程序编址上的复杂性。

2.6.1  进程的通信类型

1. 共享存储器系统

1)基于共享数据结构的通信方式 —— 低级通信。

2)基于共享存储区的通信方式 —— 高级通信。

2. 消息传递系统

信息单位:消息(报文)

实现:利用 OS 提供的一组通信命令(原语)—— 具有透明性。

根据实现方式可分成:

1)直接通信方式

2)间接通信方式

 

3. 管道通信

管道:是指连接一个读进程和一个写进程以实现它们之间通信的一个共享文件。

功能:大量的数据收发。

注意:1)互斥 2)同步 3)确定对方是否存在

2.6.2  消息传递系统的实现方法

1. 直接通信方式

是指发送进程利用 OS 所提供的发送命令(原语),直接把消息发送给目标进程。

对称寻址方式要求发送进程和接收进程都必须以显式方式提供对方的标志符。通常,OS 提供下述两条通信命令(原语):

send(receiver, message);

receive(sender, message);

应用于生产者-消费者问题,则有:

/*生产者*/
do {

    //produce an item in nextp

    send(consumer, nextp);

} while(true);

/*消费者*/
do {
    receive(producer, nextc);

    //consume the item in nextc

} while(true);

2. 间接/信箱通信方式

1)是指进程之间利用信箱的通信方式。

  1. 发送进程将发送给目标进程的消息存放到信箱中;
  2. 接收进程则从该信箱中取出对方发送给自己的消息;

消息在信箱中可以安全地保存,只允许核准的目标用户随时读取。

系统为信箱通信提供了若干条原语,分别用于信箱的创建和撤消、消息的发送和接收等。

消息的发送和接收:

send(mailbox, message);

receive(mailbox, message);

优点:在读和写时间上具有随机性。

2)信箱分为以下三类

  • 私用信箱
  • 公用信箱
  • 共享信箱

3)信箱通信关系

在利用信箱通信时,发送进程和接收进程之间存在以下四种关系:

  • 一对一关系。
  • 多对一关系,客户/服务器交互。
  • 一对多关系, 广播方式。
  • 多对多关系。  

2.6.3  消息传递系统中的几个问题

1. 消息的格式

消息头:包含控制信息,如:收/发进程名,消息长度、类型、编号等。

消息内容:

  • 定长消息:系统开销小,用户不便(特别是传长消息用户)
  • 变长消息:开销大,用户方便。

2. 进程的同步方式

不论是发送进程还是接收进程,在完成消息的发送或接收后,都存在两种可能性,即进程或者继续发送/接收或者阻塞。

1)发送进程阻塞,接收进程阻塞。主要用于进程之间紧密同步,发送进程和接收进程之间无缓冲区时。(发送进程发送完毕唤醒接收进程,自己阻塞;接收进程接收完毕唤醒发送进程,自己阻塞)

2)发送进程不阻塞,接收进程阻塞。平时,发送进程不阻塞,因而它可以尽快地把一个或多个消息发送给多个目标;而接收进程平时则处于阻塞状态,直到发送进程发来消息时才被唤醒。如:打印进程等待打印任务。

3)发送进程和接收进程均不阻塞。平时,发送进程和接收进程都在忙于自己的事情,仅当发生某事情使它无法继续运行时,才把自己阻塞起来等待。一般在发送进程和接收进程之间有多个缓冲区时。

2.6.4  消息缓冲队列通信机制

1. 数据结构

1)消息缓冲区:

typedef struct message_buffer {
    int sender;     //发送者进程标识符
    int size;       //表示消息长度
    int * text;     //指向消息正文
    //指向下一个消息缓冲区的指针
    struct message_buffer * next;
};

2)PCB 中应增加的数据项

typedef struct pcb {

    //消息队列队首指针
    struct message_buffer * mq; 
    semaphore mutex;    //消息队列互斥型信号量
    semaphore sm;       //消息队列资源型信号量

};

2. 发送原语

DJ2-6 进程通信_第1张图片

send 之后的操作由 OS 内核来执行,该过程对用户来说是透明的。

发送原语可描述如下:

void send(receiver, a) {
    //申请缓冲区
	getbuf(a.size, i);

    //将发送区a中的信息复制到消息缓冲区i中
	i.sender = a.sender;
	i.size = a.size;
	copy(i.text, a.text);
	i.next = 0;

    //获得接收进程内部的标识符j
	getid(PCBset, receiver.j);

    //将消息缓冲区插入消息队列
    wait(j.mutex);
	insert(&j.mq, i);
	signal(j.mutex);
	signal(j.sm);
}

3. 接收原语

DJ2-6 进程通信_第2张图片

接收原语可描述如下:

void receive(b) {
    //j为接收进程内部的标识符
	j = internal name;

    //将消息队列中第一个消息移出
	wait(j.sm);
	wait(j.mutex);
	remove(j.mq, i);
	signal(j.mutex);

    //将消息缓冲区i中的信息复制到接收区b
    b.sender = i.sender;
	b.size = i.size;
	copy(b.text, i.text);

    //释放消息缓冲区
    releasebuf(i);
}

plus. 练习

试说明如果使用 send_mailbox 和 receive_mailbox 原语实现打印文件的系统。

  • 欲打印的进程将要打印的文件名发送到邮箱 printer
  • 打印机假脱机将打印邮箱 printer 中出现名字的任何文件
//process wish to print
char filename[];
status = send_mailbox("printer", filename);
if(status < 0) { 
    //fail
}

//printer
char filename[];
while(true) {
    status = receive_mailbox("printer", filename);
    
    if(status < 0) { 
        //fail
    }

    print(filename);
}

你可能感兴趣的:(计算机操作系统,学习,计算机操作系统)