操作系统PV操作学习总结

    科技2022-07-11  97

    一、信号量

    整形信号量:表示系统中某种资源的数量(不满足"让权等待")。 int S=1;//初始化整型信号量S,表示当前系统中可用的资源数 void wait(int S){ //wait原语,相当于"进入区" while(S<=0); //如果资源数不够,就一直循环等待 S=S-1; //如果资源数够,占用一个资源 } void signal(int S){ //signal原语,相当于"退出区" S=S+1; //使用完资源后,退出区释放资源 } 记录型信号量:s.value<0时,|s.value|代表链表中已被阻塞的该信号进程的数目(即等待进入临界区的)遵循了"让权等待"原则。 //记录型信号量的定义 typedef struct{ int value; //剩余资源数 struct process *L; //等待队列 }semaphore; //某进程需要使用资源时,通过wait原语申请。 void wait(semaphore S){ S.value--; if(S.value<0){ block(S.L); } } //进程使用完资源后,通过signal原语释放 void wait(semaphore S){ S.value++; if(S.value<=0){ wakeup(S.L); } }

    二、信号量机制实现同步与互斥

    互斥:设置互斥信号量mutex,初值为1。 semaphore mutex=1; //初始化信号量 P1(){ ... P(mutex); //使用临界资源前需要加锁 临界区代码段... V(mutex); //使用临界资源后需要解锁 ... } P2(){ ... P(mutex); 临界区代码段... V(mutex); ... } 同步:必须保证"一前一后"(前V后P)执行的操作。设置同步信号量S,初值为0。注:同步:要为每一对前驱关系各设置一个信号量。P、V操作必须成对出现。

    二、信号量机制实现同步与互斥

    互斥:设置互斥信号量mutex,初值为1。 semaphore mutex=0; //初始化信号量,初值为0 P1(){ 代码1; V(S); 代码2} P2(){ P(S); 代码3; 代码4}

    三、生产者消费者问题

    生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。 要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。

    如何实现:

    生产者、消费者共享一个初始为空、大小为n的缓冲区缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待。缓冲区不空时,消费者才能从中取出产品,否则必须等待。缓冲区时临界资源,各进程必须互斥访问。 semaphore mutex=1; //互斥信号量,实现对缓冲区的互斥访问 semaphore empty=n; //同步信号量,表示空闲缓冲区的数量 semaphore full=0; //同步信号量,表示产品数量,即非空缓冲区的数量 producer(){ while(1){ 生产一个产品; P(empty); P(mutex); 讲产品放入缓冲区; V(mutex); V(full); } } consumer(){ while(1){ 生产一个产品; P(full); P(mutex); 从缓冲区取出一个产品; V(mutex); V(empty); 使用产品; } }

    四、读者与写者问题

    读者—写者问题(Readers-Writers problem)也是一个经典的并发程序设计问题,是经常出现的一种同步问题。计算机系统中的数据(文件、记录)常被多个进程共享,但其中某些进程可能只要求读数据(称为读者Reader);另一些进程则要求修改数据(称为写者Writer)。就共享数据而言,Reader和Writer是两组并发进程共享一组数据区,要求: (1)允许多个读者同时执行读操作; (2)不允许读者、写者同时操作; (3)不允许多个写者同时操作。

    写者优先

    semaphore rw=1; //用于实现对文件的互斥访问 int count=0; //记录当前有几个读进程在访问文件 semaphore mutex=1; //用于保证对count变量的互斥访问 semaphore w=1//用于实现"写优先" writer(){ while(1){ P(w); p(rw); 写文件... V(rw); V(w); } } reader(){ while(1){ P(w); p(mutex); if(count==0)p(rw); count++; V(mutex); V(w); 读文件... P(mutex); count--; if(count==0)V(rw); V(mutex); } }

    五、哲学家进餐问题

    有五个哲学家,他们的生活方式是交替地进行思考和进餐,哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,该哲学家进餐完毕后,放下左右两只筷子又继续思考。 约束条件 (1)只有拿到两只筷子时,哲学家才能吃饭。 (2)如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。 (3)任一哲学家在自己未拿到两只筷子吃完饭前,不会放下手中已经拿到的筷子。

    如何实现

    可以对哲学家施加一些限制条件,比如允许四个哲学家同时进餐,这样可以保证至少有一个科学家是可以拿到左右两只筷子的。 semaphore chopstick[5]={1,1,1,1,1}; //用一个信号量表示一只筷子 semaphore num=4; //限制为4个哲学家 void philosophyer(int i){ while(1){ P(num); P(chopstick[i]); P(chopstick[(i+1)%5]); ...//eat V(chopstick[i]); V(chopstick[(i+1)%5]); V(num); ...//think } } 要求奇数号哲学家先拿左边筷子,然后再拿右边的筷子,而偶数号哲学家相反。用这种方法保证如果相邻的两个奇偶号哲学家都想吃饭,那么只会有其中一个拿起第一只筷子,另一个会直接阻塞,这就避免了占有一支后再等待另一只的情况。 semaphore chopstick[5]={1,1,1,1,1}; //用一个信号量表示一只筷子 void philosophyer(int i){ if(i%2==0) while(1){ P(chopstick[(i+1)%5]); //偶数哲学家先拿右边筷子 P(chopstick[i]); ...//eat V(chopstick[(i+1)%5]); V(chopstick[i]); ...//think } else while(1){ P(chopstick[i]); //奇数哲学家先拿左边筷子 P(chopstick[(i+1)%5]); ...//eat V(chopstick[i]); V(chopstick[(i+1)%5]); ...//think } }

    六、顾客与理发师问题

    一个理发师,一把理发椅,n把等候理发的顾客椅子,如果没有顾客则理发师便在理发椅上睡觉 ,当有一个顾客到达时,首先看理发师在干什么,如果理发师在睡觉,则唤醒理发师理发,如果理发师正在理发,则查看是否有空的顾客椅子可坐, 如果有,坐下等待,如果没有,则离开。

    int chairs=5,waiting=0; //定义椅子数和正在等待顾客数量 semaphore baber=0; //理发师信号量 semaphore customer=0; //顾客信号量 semaphore mutex=1; //互斥信号量 void barber(){ while(1){ P(customer); P(mutex); waiting--; V(mutex); ...//cut V(barber); } } void comstomer(){ while(1){ P(mutex); if(waiting<chairs){ //店里还有座 waiting++; V(customer); V(mutex); P(barber); ...//get }else V(mutex); } }
    Processed: 0.011, SQL: 8