---间接寻址
&采用间接寻址传递消息时,消息不再从发送方直接发送到接收方,而是通过发送进程与接收进程共享的一个数据结构进行转换,该数据结构通常称为邮箱。
&发送进程将消息发送到指定的邮箱中,接收进程从邮箱中接受消息。
---邮箱
&邮箱不限制进程数,允许多个发送进程向邮箱发送消息,同时,也允许多个接收进程从邮箱接收消息。
---利用消息传递实现互斥
&采用“不阻塞发送,阻塞接收方式”。
&多个并发执行的发送进程和接收进程共享一个邮箱mutex,他被初始化为一个无内容的“空”消息。
&如果一个进程希望进入临界区,首先必须申请从mutex邮箱中接收一条消息。若邮箱为“空”,则该进程阻塞(接收);若进程收到邮箱中的一条消息,则进入临界区,执行完毕以后,退出临界区,并将该消息发送回邮箱mutex,如下:
Program mutualexclusion;
Const n=…;
Procedure P(i:integer);
Var msg:message;
Begin
Repeat
Receive(mutex,msg);
<临界区>;
Send(mutex,msg);
<其余部分>
Forever
End;
Begin
Creat_mailbox(mutex);
Send(mutex,null);
Parbegin
P(1);
P(2);
…
P(n)
Parend
End;
!注意
---“空”消息:代表一条消息体为“空”,但具有消息头的“真正”的一条消息,不是没有消息。
---当第一个希望进入临界区的进程执行receive(mutex,msg)语句时,从邮箱mutex中接收了这条“空”消息,进入临界区执行。这时,邮箱mutex变为“空”,即没有消息。其后执行receive(mutex,msg)语句希望进入临界区的进程被阻塞。
---当进入临界区的进程执行完临界区的代码,退出临界区时,执行send(mutex,msg)语句,将这条“空”消息归还给邮箱mutex,并唤醒一个阻塞进程,使其取走这条消息,进入临界区执行。
---可见,控制进程互斥进入临界区的这条消息本身可以不含任何有用的内容,他仅被当作进程是否进入临界区的一种凭证,或令牌。
---只要保证邮箱中最多只有一条消息,就能保证只允许一个进程进入临界区,从而实现进程互斥使用临界资源。
+利用消息传递解决:生产者-消费者问题
---共使用了capacity条消息,类似与共享内存缓冲区中的capacity存储单元。
---消费者首先将capacity条“空”消息发送给生产者。当生产者向消费者传递一条数据时它取走一条“空”消息,并发回一条填充了内容的消息。
---通过这种方式进行数据传送,系统中的总消息数保持不变,所以,消息可以存放在预知数量的内存中。
+生产者/消费者同步
---如果生产者生产数据的速度比消费者消费数据的速度快,则所有的“空”消息最终都将被填满,于是生产者将因为接收不到“空”消息而被阻塞,等待消费者取走带有数据的消息,然后返回一条“空”消息。
---如果消费者消费数据的速度更快,则消费者将因为接收不到“数据”消息而阻塞,直到生产者生产并发送来一条“数据”消息。
Program mutualexclusion;
Const
Capacity =…:
Null =…:
Procedure producer;
Var pmsg:message;
Begin
While true do
Begin
Receive(mayproduce,pmsg);
Pmsg=produce;
Send(mayconsume,pmsg)
End
End;
Procedure consumer
Var cmsg:message;
Begin
While true do
Begin
Receive(mayconsume,cmsg);
Consume(cmsg);
Send(mayproduce,null);
End
End;
Begin
Create_mailbox(mayproduce);
Create_mailbox(mayconsume);
For i=1 to capacity do send(mayproduce,null);
Parbegin
Producer;
Consumer;
Parend
end |