资源预览内容
第1页 / 共50页
第2页 / 共50页
第3页 / 共50页
第4页 / 共50页
第5页 / 共50页
第6页 / 共50页
第7页 / 共50页
第8页 / 共50页
第9页 / 共50页
第10页 / 共50页
亲,该文档总共50页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
12.3.4 信号量(信号量(Semaphore) 1965年由著名的荷兰计算机科学家年由著名的荷兰计算机科学家Dijkstra提出,提出, 其基本思路是用一种新的变量类型(其基本思路是用一种新的变量类型(semaphore) 来记录当前可用资源的数量。来记录当前可用资源的数量。 有两种实现方式:有两种实现方式:1)semaphore的取值必须大于的取值必须大于 或等于或等于0。0表示当前已没有空闲资源,而正数表表示当前已没有空闲资源,而正数表 示当前空闲资源的数量;示当前空闲资源的数量;2)semaphore的取值可的取值可 正可负,负数的绝对值表示正在等待进入临界区正可负,负数的绝对值表示正在等待进入临界区 的进程个数。的进程个数。 信号量是由操作系统来维护的,用户进程只能通信号量是由操作系统来维护的,用户进程只能通 过初始化和两个标准过初始化和两个标准原语原语(P、V原语)来访问。原语)来访问。 初始化可指定一个非负整数,即空闲资源总数。初始化可指定一个非负整数,即空闲资源总数。2 P、V原语作为操作系统内核代码的一部分,是一原语作为操作系统内核代码的一部分,是一 种不可分割的原子操作(种不可分割的原子操作(atomic action),在其),在其 运行时,不会被时钟中断所打断;运行时,不会被时钟中断所打断; P、V原语包含有进程的阻塞和唤醒机制,因此原语包含有进程的阻塞和唤醒机制,因此 在进程等待进入临界区时不会浪费在进程等待进入临界区时不会浪费CPU时间;时间; P原语:原语:P是荷兰语是荷兰语Proberen(测试)的首字母。(测试)的首字母。 申请一个空闲资源(把信号量减申请一个空闲资源(把信号量减1),若成功,),若成功, 则退出;若失败,则该进程被阻塞;则退出;若失败,则该进程被阻塞; V原语:原语:V是荷兰语是荷兰语Verhogen(增加)的首字母。(增加)的首字母。 释放一个被占用的资源(把信号量加释放一个被占用的资源(把信号量加1),如果),如果 发现有被阻塞的进程,则选择一个唤醒之。发现有被阻塞的进程,则选择一个唤醒之。3信号量和P、V原语的实现信号量结构体类型的定义信号量结构体类型的定义typedef struct int count;/ 计数变量计数变量 struct PCB *queue;/ 进程等待队进程等待队列列 semaphore;4P原语:申请一个资源原语:申请一个资源P( semaphore S) -S.count;/表示申请一个资源表示申请一个资源; if (S.count 0)/表示没有空闲资源表示没有空闲资源; 该进程进入等待队列该进程进入等待队列S.queue末尾末尾; 阻塞该进程阻塞该进程; 调用进程调度器;调用进程调度器; 5 V原语:释放一个资源原语:释放一个资源V( semaphore S) +S.count;/表示释放一个资源表示释放一个资源; if (S.count = 0) /表示有进程被阻塞表示有进程被阻塞; 从等待队列从等待队列S.queue中取出一个进程中取出一个进程; 把该进程改为就绪状态,插入就绪队列把该进程改为就绪状态,插入就绪队列 6Windows 2000CreateSemaphore(创建信号量)(创建信号量)WaitForSingleObject(P操作)操作)ReleaseSemaphore(V操作)操作) COS-IIosSemCreate(创建信号量)(创建信号量)osSemPend (P操作)操作)osSemPost(V操作)操作)7利用信号量来实现进程互斥int count; / 共享变量(临界资源)共享变量(临界资源)semaphore mutex;/ 互斥信号量,初始化为互斥信号量,初始化为?非临界区非临界区P(mutex);临界区临界区V(mutex);非临界区非临界区P1非临界区非临界区P(mutex);临界区临界区V(mutex);非临界区非临界区P2非临界区非临界区P(mutex);临界区临界区V(mutex);非临界区非临界区P382.3.5 进程的同步进程的同步进程间的进程间的同步同步是指多个进程中发生的事件是指多个进程中发生的事件存在某种时序关系,因此在各个进程之间存在某种时序关系,因此在各个进程之间必须协同合作,相互配合,使各个进程按必须协同合作,相互配合,使各个进程按一定的速度执行,以共同完成某一项任务。一定的速度执行,以共同完成某一项任务。同步:同步:合作合作。 互斥:互斥:竞争竞争。只考虑基于信号量的同步问题。只考虑基于信号量的同步问题。9如何实现如何实现A先执行,然后先执行,然后B执行?执行?A;V(S);进程进程P1 P(S);B;进程进程P2 配对配对先后先后S初始值为初始值为0.A(先先);.进程进程P1 信号量信号量S初始值为?初始值为?.B(后后);.进程进程P2 10while(1) . A; V(S); .进程进程P1 S初始值为初始值为1while(1) . P(S); B; .进程进程P2 11【例子例子1】 合作进程的执行次序合作进程的执行次序 用进程流图来描述各进程合作完成某一任务的次序,用进程流图来描述各进程合作完成某一任务的次序,其规则如下:其规则如下:12用信号量及用信号量及P、V操作来描述左图操作来描述左图1、说明进程的同步关系、说明进程的同步关系 进进程程P1、P2可可并并行行执执行行,P3的的执执行行必必须须等等待待P1、P2都都完完成成后后才才能能开始执行。开始执行。 几个同步关系?几个同步关系?2、设置信号量,说明含义、初值。、设置信号量,说明含义、初值。 S13 = 0 表示进程表示进程P1尚未执行完成;尚未执行完成; S23 = 0 表示进程表示进程P2尚未执行完成;尚未执行完成;13main() /均初始化为均初始化为0 semaphore S13, S23; cobegin P1; P2; P3; coend3. 写出程序描述写出程序描述P1( ) /进程进程P1 V(S13);P2( ) /进程进程P2 V(S23);P3( ) /进程进程P3 P(S13); P(S23); 14【例子例子2】 司机与售票员司机与售票员while(上班时间上班时间) 发动汽车;发动汽车; 正常运行;正常运行; 到站停车;到站停车;while(上班时间上班时间) 关闭车门;关闭车门; 售票;售票; 打开车门;打开车门;公车司机公车司机售票员售票员1、说明进程的同步关系说明进程的同步关系只有关闭车门以后,才能启动汽车;只有关闭车门以后,才能启动汽车;只有停车以后,才能打开车门。只有停车以后,才能打开车门。15while(上班时间上班时间) P(S_DoorClose); 发动汽车;发动汽车; 正常运行;正常运行; 到站停车;到站停车; V(S_Stop); 公车司机公车司机while(上班时间上班时间) 关闭车门;关闭车门; V(S_DoorClose); 售票;售票; P(S_Stop); 打开车门;打开车门;售票员售票员semaphore S_DoorClose;/ 初始为初始为0semaphore S_Stop;/ 初始为初始为0先关门先关门后开车后开车先停车先停车后开门后开门2、设置信号量,说明含义、初值。、设置信号量,说明含义、初值。3. 写出程序描述写出程序描述16【例子例子3】共享缓冲区的合作进程的同步共享缓冲区的合作进程的同步设有一个缓冲区设有一个缓冲区buffer,大小为一个字节。,大小为一个字节。Compute进程不断产生字符,送进程不断产生字符,送buffer,Print进程从进程从buffer中中取出字符打印。如不加控制,会出现多种打印结果,取出字符打印。如不加控制,会出现多种打印结果,这取决于这两个进程运行的相对速度。在这众多的这取决于这两个进程运行的相对速度。在这众多的打印结果中,只有打印结果中,只有Compute和和Print进程的运行刚好进程的运行刚好匹配的一种是正确的,其它均为错误。匹配的一种是正确的,其它均为错误。while(计算未完成计算未完成) 得到一个计算结果得到一个计算结果; 将数据送到缓冲区;将数据送到缓冲区;Computewhile(打印未完成打印未完成) 从缓冲区中取一数据;从缓冲区中取一数据; 打印该数据;打印该数据;Print17bufferComputePrint正确:正确:“ABCD”错误:错误:“BB”错误:错误:“AA”“ABCD”181. 问题分析,弄清楚同步关系:问题分析,弄清楚同步关系:要保证打印结果的正确,要保证打印结果的正确,Compute和和Print进程必进程必须遵循以下同步规则:须遵循以下同步规则:当当Compute把数据送入把数据送入buffer后,后,Print才能从才能从buffer中取,否则它必须等待(先存后取);中取,否则它必须等待(先存后取);当当Print从从buffer取走数据后,取走数据后,Compute才能将才能将新数据送新数据送buffer,否则也须等待(先取后存),否则也须等待(先取后存)computeprintcomputeprintcomputeprintt1t0t2t3t4t5t6讨论一个信号量是否可行?一个信号量是否可行?19semaphore S_Buffer; / 缓冲区是否有空间,初值缓冲区是否有空间,初值1semaphore S_Data;/ 是否有数据需打印,初值是否有数据需打印,初值02. 设置信号量,说明含义、初值。设置信号量,说明含义、初值。3. 写出程序描述。写出程序描述。while(计算未完成计算未完成) 得到一个计算结果得到一个计算结果; P(S_Buffer); 将数据送到缓冲区;将数据送到缓冲区; V(S_Data);Computewhile(打印未完成打印未完成) P(S_Data); 从缓冲区中取一数据;从缓冲区中取一数据; V(S_Buffer); 打印该数据;打印该数据;Print202.4 经典的经典的IPC问题问题 生产者生产者消费者问题消费者问题 哲学家就餐问题哲学家就餐问题 读者读者写者问题写者问题 用信号量来解决,主要问题:如何选择信号量,用信号量来解决,主要问题:如何选择信号量,如何安排如何安排P、V原语的顺序。原语的顺序。212.4.1 生产者生产者消费者问题消费者问题两个进程(生产者和消费者)共享一个公有两个进程(生产者和消费者)共享一个公有的、固定大小的缓冲区,生产者不断地制造的、固定大小的缓冲区,生产者不断地制造产品,并把它放入缓冲区,而消费者不断地产品,并把它放入缓冲区,而消费者不断地把产品取出来,并且使用它。要求这两个把产品取出来,并且使用它。要求这两个进程相互协调,正确地完成各自的工作。进程相互协调,正确地完成各自的工作。问题描述2212345678生产者生产者生产生产消费者问题消费者问题消费方向消费方向生产方向生产方向消费者消费者23问题分析对于生产者进程:制造一个产品,当要送入缓冲区对于生产者进程:制造一个产品,当要送入缓冲区时,要检查缓冲区是否有空位,若是,才可将产品时,要检查缓冲区是否有空位,若是,才可将产品送入缓冲区,并在必要时通知消费者;否则等待;送入缓冲区,并在必要时通知消费者;否则等待;对于消费者进程:当它去取产品时,先要检查缓冲对于消费者进程:当它去取产品时,先要检查缓冲区中是否有产品可取,若有,则取走一个,并在必区中是否有产品可取,若有,则取走一个,并在必要时通知生产者;否则等待。要时通知生产者;否则等待。这种相互等待,并互通信息就是典型的进程同步。这种相互等待,并互通信息就是典型的进程同步。同时,缓冲区是个同时,缓冲区是个临界资源临界资源,因此,各个进程在,因此,各个进程在使用缓冲区的时候,还有一个互斥的问题。使用缓冲区的时候,还有一个互斥的问题。24semaphore S_Buffer_Num;/ 空闲的缓冲区个数,空闲的缓冲区个数,/ 初值为初值为Nsemaphore S_Product_Num; / 缓冲区当中的产品个缓冲区当中的产品个/ 数,初值为数,初值为0semaphore S_Mutex; / 用于互斥访问的信号用于互斥访问的信号/ 量,初值为量,初值为1信号量的定义信号量的定义main( ) cobegin producer( ); consumer( ); coend25void producer(void) int item; while(TRUE) item = produce_item( ); / 制造一个产品制造一个产品 P(S_Buffer_Num);/ 是否有空闲缓冲区是否有空闲缓冲区 P(S_Mutex);/ 进入临界区进入临界区 insert_item(item);/ 产品放入缓冲区产品放入缓冲区 V(S_Mutex);/ 离开临界区离开临界区 V(S_Product_Num);/ 新增了一个产品新增了一个产品 生产者进程生产者进程while(计算未完成计算未完成) 得到一个计算结果得到一个计算结果; P(S_Buffer); 将数据送到缓冲区;将数据送到缓冲区; V(S_Data);Compute26void consumer(void) int item; while(TRUE) P(S_Product_Num);/ 缓冲区中有无产品缓冲区中有无产品 P(S_Mutex);/ 进入临界区进入临界区 item = remove_item( )/ 从缓冲区取产品从缓冲区取产品 V(S_Mutex);/ 离开临界区离开临界区 V(S_Buffer_Num);/ 新增一个空闲缓冲新增一个空闲缓冲区区 consume_item(item);/ 使用该产品使用该产品 消费者进程消费者进程while(打印未完成打印未完成) P(S_Data); 从缓冲区中取一数据;从缓冲区中取一数据; V(S_Buffer); 打印该数据;打印该数据;PrintWhy 互斥?互斥?27void consumer(void) int item; while(TRUE) P(S_Product_Num); P(S_Mutex); item = remove_item( ) consume_item(item); V(S_Mutex); V(S_Buffer_Num); 消费者进程消费者进程void producer(void) int item; while(TRUE) P(S_Buffer_Num); P(S_Mutex); item = produce_item( ); insert_item(item); V(S_Mutex); V(S_Product_Num); 生产者进程生产者进程282.4.2 哲学家就餐问题哲学家就餐问题1965年,由年,由Dijkstra提出并解决,后来逐渐提出并解决,后来逐渐成为该领域的一个经典问题,或者说,是一成为该领域的一个经典问题,或者说,是一块试金石,用来试验新的进程同步方法的优块试金石,用来试验新的进程同步方法的优劣。劣。29五个哲学家围坐在一张圆桌五个哲学家围坐在一张圆桌旁,每个哲学家面前都摆着旁,每个哲学家面前都摆着一大盘意大利面条,面条非一大盘意大利面条,面条非常滑,所以每个哲学家都需常滑,所以每个哲学家都需要两把叉子才能进餐,在相要两把叉子才能进餐,在相邻两个盘子之间,只有一把邻两个盘子之间,只有一把叉子。叉子。 桌面的布局见右图。桌面的布局见右图。问题描述本图摘自本图摘自 “Modern Operating Systems”012340123430每个哲学家的动作只有两种:进餐和思考。当一个每个哲学家的动作只有两种:进餐和思考。当一个哲学家感到饥饿时,他试图去获得他左边和右边的哲学家感到饥饿时,他试图去获得他左边和右边的两把叉子(一次取一把,顺序无关),然后才能开两把叉子(一次取一把,顺序无关),然后才能开始进餐。吃完以后,他需要把两把叉子放回原处,始进餐。吃完以后,他需要把两把叉子放回原处,然后继续思考。然后继续思考。问题是:如何保证哲学家们的动作有序进行?如:问题是:如何保证哲学家们的动作有序进行?如:不出现相邻者同时要求进餐,也不出现有人永远拿不出现相邻者同时要求进餐,也不出现有人永远拿不到叉子。不到叉子。问题描述(续)31方案方案1#define N 5 / 哲学家个数哲学家个数void philosopher(int i) / 哲学家编号:哲学家编号:0 4 while(TRUE) think( );/ 哲学家在思考哲学家在思考 take_fork(i);/ 去拿左边的叉子去拿左边的叉子 take_fork(i + 1) % N);/ 去拿右边的叉子去拿右边的叉子 eat( );/ 吃面条中吃面条中. put_fork(i);/ 放下左边的叉子放下左边的叉子 put_fork(i + 1) % N);/ 放下右边的叉子放下右边的叉子 不正确,可能导致死锁。不正确,可能导致死锁。32方案方案2while(1)/ 去拿两把叉子去拿两把叉子 take_fork(i);/ 去拿左边的叉子去拿左边的叉子 if(fork(i+1)%N) / 右边叉子还在吗右边叉子还在吗 take_fork(i + 1) % N);/ 去拿右边的叉子去拿右边的叉子 break;/ 两把叉子均到手两把叉子均到手 else / 右边叉子已不在右边叉子已不在 put_fork(i);/ 放下左边的叉子放下左边的叉子 wait_some_time( );/ 等待一会儿等待一会儿 对拿叉子的过程进行了改进,但仍不正确对拿叉子的过程进行了改进,但仍不正确33方案方案3while(1)/ 去拿两把叉子去拿两把叉子 take_fork(i);/ 去拿左边的叉子去拿左边的叉子 if(fork(i+1)%N) / 右边叉子还在吗右边叉子还在吗 take_fork(i + 1) % N);/ 去拿右边的叉子去拿右边的叉子 break;/ 两把叉子均到手两把叉子均到手 else / 右边叉子已不在右边叉子已不在 put_fork(i);/ 放下左边的叉子放下左边的叉子 wait_random_time( ); / 等待随机长时间等待随机长时间 等待时间随机变化。可行,但非万全之策等待时间随机变化。可行,但非万全之策34方案方案4semaphore mutex / 互斥信号量,初值互斥信号量,初值1void philosopher(int i) / 哲学家编号哲学家编号i:04 while(TRUE) think( );/ 哲学家在思考哲学家在思考 P(mutex);/ 进入临界区进入临界区 take_fork(i);/ 去拿左边的叉子去拿左边的叉子 take_fork(i + 1) % N);/ 去拿右边的叉子去拿右边的叉子 eat( );/ 吃面条中吃面条中. put_fork(i);/ 放下左边的叉子放下左边的叉子 put_fork(i + 1) % N);/ 放下右边的叉子放下右边的叉子 V(mutex);/ 退出临界区退出临界区 互斥访问。正确,但每次只允许一人进餐互斥访问。正确,但每次只允许一人进餐35方案方案4的缺点:的缺点:它把就餐(而不是叉子)看成是必须互斥访问的它把就餐(而不是叉子)看成是必须互斥访问的临界资源,因此会造成(叉子)资源的浪费。从临界资源,因此会造成(叉子)资源的浪费。从理论上说,如果有五把叉子,应允许两个不相邻理论上说,如果有五把叉子,应允许两个不相邻的哲学家同时进餐。的哲学家同时进餐。36S1 思考中思考中S2 进入饥饿状态;进入饥饿状态;S3 如果左邻居或右邻居正在进餐,等待;否则转如果左邻居或右邻居正在进餐,等待;否则转S4S4 拿起两把叉子;拿起两把叉子;S5 吃面条吃面条S6 放下左边的叉子;放下左边的叉子;S7 放下右边的叉子;放下右边的叉子;S8 新的一天又开始了,转新的一天又开始了,转S1哲学家就餐问题的解答思路思路(1)哲学家自己怎么来解决这个问题?哲学家自己怎么来解决这个问题?指导原则:要么不拿,要么就拿两把叉子。指导原则:要么不拿,要么就拿两把叉子。37S1 思考中思考中S2 进入饥饿状态;进入饥饿状态;S3 如果左邻居或右邻居正在进餐,如果左邻居或右邻居正在进餐,进入阻塞状态;进入阻塞状态; 否则转否则转S4S4 拿起两把叉子;拿起两把叉子;S5 吃面条吃面条S6 放下左边的叉子,放下左边的叉子,看看左邻居现在能否进餐看看左邻居现在能否进餐 (饥饿状态、两把叉子都在),若能则唤醒之;(饥饿状态、两把叉子都在),若能则唤醒之;S7 放下右边的叉子,放下右边的叉子,看看右邻居现在能否进餐,看看右邻居现在能否进餐, 若能,唤醒之;若能,唤醒之;S8 新的一天又开始了,转新的一天又开始了,转S1思路思路(2)计算机程序怎么来解决这个问题?计算机程序怎么来解决这个问题?指导原则:不能浪费指导原则:不能浪费CPU时间;进程间相互通信。时间;进程间相互通信。38思路思路(3) 怎么样来编写程序?怎么样来编写程序?1.必须有一个数据结构,来描述每个哲学家的必须有一个数据结构,来描述每个哲学家的当前当前状态状态;2.该数据结构是一个临界资源,各个哲学家对它的该数据结构是一个临界资源,各个哲学家对它的访问应该互斥地进行访问应该互斥地进行进程互斥进程互斥;3.一个哲学家吃饱后,可能要唤醒它的左邻右舍,一个哲学家吃饱后,可能要唤醒它的左邻右舍,两者之间存在着同步关系两者之间存在着同步关系进程同步进程同步;39数据结构的定义数据结构的定义#define N5/ 哲学家个数哲学家个数#define LEFT(i+N-1)%N / 第第i个哲学家的左邻居个哲学家的左邻居#define RIGHT (i+1)%N/ 第第i个哲学家的右邻居个哲学家的右邻居#define THINKING0/ 思考状态思考状态#define HUNGRY1/ 饥饿状态饥饿状态#define EATING2/ 进餐状态进餐状态int stateN;/ 记录每个人的状态记录每个人的状态semaphore mutex;/ 互斥信号量,初值互斥信号量,初值1semaphore sN;/ 每人一个信号量,每人一个信号量,040void philosopher(int i) / i的取值:的取值:0到到N1 while(TRUE)/ 封闭式开发,一直循环封闭式开发,一直循环 think( ); / 思考中思考中 take_forks(i);/ 拿到两把叉子或被阻塞拿到两把叉子或被阻塞 eat( );/ 吃面条中吃面条中 put_forks(i);/ 把两把叉子放回原处把两把叉子放回原处 函数函数philosopher的定义的定义S1S2S4S5S6S741/ 功能:要么拿到两把叉子,要么被阻塞起来。功能:要么拿到两把叉子,要么被阻塞起来。void take_forks(int i) / i的取值:的取值:0到到N1 P(mutex);/ 进入临界区进入临界区 statei = HUNGRY;/ 我饿了!我饿了! test(i); / 试图拿两把叉子试图拿两把叉子 V(mutex);/ 退出临界区退出临界区 P(si);/ 没有叉子便阻塞没有叉子便阻塞函数函数take_forks的定义的定义42void test(int i) / i的取值:的取值:0到到N1 if(statei = HUNGRY & stateLEFT != EATING & stateRIGHT != EATING) statei = EATING;/ 两把叉子到手两把叉子到手 V(si);/ 第第i人可以吃饭了人可以吃饭了 函数函数test的定义的定义43/ 功能:把两把叉子放回原处,并在需要的时候,功能:把两把叉子放回原处,并在需要的时候,/ 去唤醒左邻右舍。去唤醒左邻右舍。void put_forks(int i) / i的取值:的取值:0到到N1 P(mutex);/ 进入临界区进入临界区 statei = THINKING;/ 交出两把叉子交出两把叉子 test(LEFT); / 看左邻居能否进餐看左邻居能否进餐 test(RIGHT);/ 看右邻居能否进餐看右邻居能否进餐 V(mutex);/ 退出临界区退出临界区函数函数put_forks的定义的定义442.4.3 读者读者写者问题写者问题在一个航空定票系统当中,有很多个竞争的在一个航空定票系统当中,有很多个竞争的进程想要访问(读、写)系统的数据库。访进程想要访问(读、写)系统的数据库。访问规则是:在任何时候,可以允许多个进程问规则是:在任何时候,可以允许多个进程同时来读,但如果有一个进程想要更新同时来读,但如果有一个进程想要更新 (写写)该数据库,则其他的任何进程都不能访问,该数据库,则其他的任何进程都不能访问,包括读者和写者。问题是:怎么样来编程实包括读者和写者。问题是:怎么样来编程实现读者和写者。现读者和写者。问题描述45问题分析任何时候任何时候“写者写者”最多只允许一个,而最多只允许一个,而“读者读者”可以有多个:可以有多个: “读读写写”是互斥的;是互斥的; “写写写写”是互斥的;是互斥的; “读读读读”是允许的;是允许的;46基于读者优先策略的方法基于读者优先策略的方法假设读者来:假设读者来:1 1)若有其它读者在读,则不论是否有写者在等,)若有其它读者在读,则不论是否有写者在等, 新读者都可以读(读者优先);新读者都可以读(读者优先);2 2)若无读者、写者,则新读者也可以读;)若无读者、写者,则新读者也可以读;3 3)若无读者,且有写者在写,则新读者等待;)若无读者,且有写者在写,则新读者等待;假设写者来:假设写者来:1 1)若有读者,则新写者等待;)若有读者,则新写者等待;2 2)若有其它写者,则新写者等待;)若有其它写者,则新写者等待;3 3)若无读者和写者,则新写者可以写;)若无读者和写者,则新写者可以写;47q 需要设置一个计数器需要设置一个计数器rcrc,用来记录并发,用来记录并发 运行的读者个数;运行的读者个数;q 对于各个读者而言,该计数器是一个临对于各个读者而言,该计数器是一个临 界资源,对它的访问必须互斥进行,因界资源,对它的访问必须互斥进行,因 此设置一个互斥信号量此设置一个互斥信号量S_mutexS_mutex;q 对于各个写者而言、写者与所有的读者对于各个写者而言、写者与所有的读者 而言,数据库是一个临界资源,对它的而言,数据库是一个临界资源,对它的 访问必须互斥地进行,因此设置一个互访问必须互斥地进行,因此设置一个互 斥信号量斥信号量S_dbS_db。48int rc = 0;/ 并发读者的个数并发读者的个数semaphore S_mutex;/ 对对rc的互斥信号量,初值的互斥信号量,初值1semaphore S_db;/ 对数据库的信号量,初值对数据库的信号量,初值1读者读者写者问题的一个解答写者问题的一个解答void writer(void) while(TRUE) think_up_data( ); / 生成数据,非临界区生成数据,非临界区 P(S_db); / 希望访问数据库希望访问数据库 write_data_base( ); / 更新数据库更新数据库 V(S_db); / 退出临界区退出临界区 49void reader(void) while(TRUE) P(S_mutex); / 互斥地访问计数器互斥地访问计数器rc rc +; / 新增了一个读者新增了一个读者 if(rc = 1) P(S_db); / 如果是第一个读者如果是第一个读者 V(S_mutex); / 退出对退出对rc的访问的访问 read_data_base( ); / 读取数据库的内容读取数据库的内容 P(S_mutex); / 互斥地访问计数器互斥地访问计数器rc rc -; / 减少一个读者减少一个读者 if(rc = 0) V(S_db); / 如果是最后一个读者如果是最后一个读者 V(S_mutex); / 退出对退出对rc的访问的访问 use_data_read( ); / 使用数据,非临界区使用数据,非临界区 50对于基于读者优先策略的方法,只要有对于基于读者优先策略的方法,只要有一个读者处于活动状态,后来的读者都一个读者处于活动状态,后来的读者都会被接纳。如果读者源源不断地出现的会被接纳。如果读者源源不断地出现的话,那么写者就始终处于阻塞状态。话,那么写者就始终处于阻塞状态。
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号