首页 > 代码库 > 操作系统:进程间的相互作用(多线程基础)
操作系统:进程间的相互作用(多线程基础)
进程间的相互作用
两种相互作用
同步
多个相关进程在执行次序上的协调。
制约关系:直接制约。
如图所示:一个进程在执行操作的时候,另一个进程必须等待,体现在次序上的等待和协调,并不争夺临界资源。
互斥
多个进程因为争夺临界资源二相互排斥执行的过程称为进程的互斥。
临界资源:也称为独占资源,是指在一段时间内只允许一个进程访问的资源。
制约关系:间接制约。
解决并发进程的问题
一.加锁法——自旋锁
思路:
设置一个共享变量W (锁) ,初值为0。当一个进程想进入其临界区(进程中涉及临界资源的程序段)时,它首
先测试这把锁:如果锁的值为0,则进程将其置为1并进入临界区。若锁已经为1,则进程等待直到其变成0。
实现:
加锁原语:LOCK(W) :L: if W=1 then goto L else W=1;
解锁原语:UNLOCK(W):W=0;
二.信号量和PV操作
信号量:
?说明:
表示资源的实体——是一个与队列有关的整型变量。
说明:其值只能通过初始化操作和P、V操作来访问。
? 类型:
公用信号量:用于进程间的互斥,初始值通常为1.
私有信号量:用于进程间的同步,初始值通常为0或N .
?P操作(Wait操作):
proberen——检查。意味着请求分配一个单位资源。
S=S-1 if(S<0) { //调用进程被阻塞,进入S的等待队列 }
?V操作(Signal操作):
荷兰语“verhogen”——“增量”之意,意味着释放/增加一个单位资源。
S=S+1; if(S<=0) { //从S的等待队列中唤醒一个进程使其进入就绪状态 }
?使用PV实现互斥
?使用PV实现进程同步
IPC经典问题
生产者消费者问题(有限缓存问题)
描述:生产者和消费者共享n个缓冲区,生产者生产产品放入缓冲区,消费者从缓冲区中取产品消费。请写出能够正确反映它们逻辑关系的代码
两个隐含条件:
1.消费者和生产者数量不固定。
2.消费者和生产者不能同时使用缓存区。
行为分析:
生产者:生产产品,放置产品(有空缓冲区)。
消费者:取出产品(有产品),消费产品。
行为关系:
生产者之间:互斥(放置产品)
消费者之间:互斥(取出产品)
生产者与消费者之间:互斥(放/取产品) 同步(放置——取出)
信号量设置:
semaphore mutex =1;//互斥
semaphore empty=n;//空闲数量
semaphore full=0;//产品数量
伪代码:
semaphore mutex=1 //互斥 semaphore empty=n //缓冲区空闲数 semaphore full=0 //产品数量 生产者: while(1) { product; //生产 p(empty); p(mutex); add to buffer;//放置产品 v(mutex); v(full) } 消费者: while(1) { p(full); p(mutex); get from buffer;//取出产品 v(mutex); v(empty) conseume; //消耗 }
读者写者问题
描述:一个数据对象(文件、记录)可以为多个并发进程共享。其中有的进程只需要读其中的内容,我们称为“读者”;有的进程负责更新(读写)其中内容,我们称为“写者”。
规定:“读者”可以同时读取共享数据对象;“写者”不能和其它任何进程同时访问共享数据对象。
行为分析:
?读进程的行为:
- 系统中会有多个读进程同时访问共享数据。
- 我们可以将它们分为三类:第一个进入的读进程(占有资源),最后一个离开的读进程(释放资源)和其他读进程。
- 我们需要设置一个计数器readnum来记录读进程的数目。
?写进程的行为:排他性的使用资源。
?确定同步与互斥关系:
读者-读者:互斥访问readnum
读者-写者:互斥访问Data
写者-写者:互斥访问Data
?确定临界资源:
Data,readnum
信号量设置:
int readnum=0;
semaphore mutex=1;//公用信号量,用于readnum的互斥。
semaphore write=1;//公用信号量,用于Data访问的互斥。
伪代码:
int readnum=0; //计数,用于记录读者的数目 semaphore mutex=1; //公用信号量,用于readnum互斥 semaphore write=1; //公用信号量,用于Data访问的互斥, 读者: p(mutex) //对readnum互斥 readnum++; if(readnum==1) P(write) //申请使用data资源 V(mutext) //释放readnum reading; p(mutex) //对readnum互斥 readnum--; if(readnum==0) V(write) //释放data资源 V(mutext) //释放readnum 写者: //P(mutex) P(write) //write本身已经互斥 writing; v(wirte) //V(mutex)
理发师问题
描述:理发店有一位理发师和一把理发椅。如果没有顾客,则理发师在理发椅上睡觉;当有顾客到达时,如理发师在睡觉则唤醒他理发,如果理发师正忙着理发,则坐在椅上等待。 编写程序实现理发师和顾客行为的正确描述。
行为分析:
?理发师行为:睡觉、理发。没有顾客睡觉,有顾客理发。
?顾客行为:理发或等待。
?相互作用:
理发师与顾客之间:同步
顾客与顾客之间:无
信号量设置:
semaphore customers=0; //customers表示等候理发的顾客数量
semaphore barbers=0; //barbars表示等候顾客的理发师数量
伪代码:
semaphore customers=0; //customers表示等候理发的顾客数量 semaphore barbers=0; //barbars表示等候顾客的理发师数量 理发师代码: while(1) { p(customers) //检查是否有顾客 v(barbers) //告诉顾客有发型师 Cut_hair(); } 顾客代码: V(customers) p(barbers); Get_hair();
这里主要体现了进程的同步。如有疑问,请看信号量介绍的同步实现。
增加条件:理发店有n把椅子,顾客到达时如果理发师空闲则理发,如果理发师忙,则看椅子上是否还有空位置,有空位置等待,没有空位置就离开。
伪代码:
semaphore customers=0; //customers表示等候理发的顾客数量 semaphore barbers=0; //barbars表示等候顾客的理发师数量 int waiting =0; //等待人数 semaphore mutex=1; //用于waiting的互斥 理发师进程: while(1) { p(customers) //检查是否有顾客 P(mutex); waiting=waiting-1; v(mutex); v(barbers) Cut_hair(); } 顾客进程: P(mutex) //占空椅子的操作是互斥的,即一个一个占 if(waiting<n) then //如果座位未满 { waiting=waiting+1; V(mutex); V(customers); P(barbers); //检测是否有理发师 Get_haircut(); } else { V(mutex); //表示座位已经满了 }
使用PV操作的注意事项
1.P、V操作(对同一信号量)总是成对出现的;互斥操作时他们处于同一进程中;同步操作时他们处于不同进程中。
2.信号量初始值的设置和P、V操作的位置及次序是关键,要十分小心的设置,一定要保持正确的逻辑关系和较高的执行效率。
操作系统:进程间的相互作用(多线程基础)