操作系统中消费者与生产者的同步互斥问题

在操作系统中,我们有进程,进程会占用资源,有些资源是可以共享的,但有些资源是只允许一个占用,不能共享,只有当占用的线程用完释放后,下一个需要用的线程才可以申请使用,这样的资源便是临界资源。属于临界资源的硬件有,打印机,磁带机等;软件有消息队列,变量,数组,缓冲区等。诸进程间采取互斥方式,实现对这种资源的共享。

消费者和生产者就金典的讲述了消费者与生产者共享“缓存区”的多线程同步问题。

基本描述:

同步关系

生产者负责生产产品,将产品放入仓库(“缓冲区”),然后消费者就从仓库里取件,然后消费。这里的仓库(“缓冲区”),就是是两者并发进行的条件。在生产和消费之间,必须满足同步,也就是不允许消费者从空库里取货,也不允许生产者向一个已经装满的仓库中放货,要想有序达成循环,就必须同步。

互斥关系

生产者和消费者,哪里存在互斥呢?

当然是二者对于缓冲区存在互斥问题,哪里来的互斥?你想想,生产者和消费者是同步运行的,肯定会遇到两者同时用缓存区的时候,如果同时用的话,那么产品数,和消费数就会不一致(例如,原来的产品数是num=1,现在缓冲区不但生产了(num+1=2),还取走了(num=1-0)这导致num变为0了,此时的变量二者用的都是num=1)这样就会导致结果出问题。对于这样的问题就必须对缓冲区进行互斥。

分析

对于同步问题和互斥问题,我们可以利用信号量机制来解决,什么是信号量呢?顾名思义就是用来做标记的信号。

这里我们可以设置信号量mutex作为互斥信号量,用于可控制互斥缓冲池,初值为1。信号量 full 用于记录缓冲池中满缓冲区数,初值为 0 ;信号量 empty 用于记录缓冲池中空缓冲区数,初值为 n。

PV操作的理解

什么是P 操作什么是V操作呢?P和V的取名好像是由于某个人来命名的不太了解。

我给大家谈谈我对于PV操作的理解吧,PV操作实质上就是对临界资源进行加锁的机制,使得许多进程可以对临界资源进行互斥访问,上面分析的信号量就对于这种机制起到了至关重要的作用。

扫描二维码关注公众号,回复: 10081048 查看本文章

P操作:P操作就是对资源进行申请

P操作原语动作如下:(原语就是若干条指令组成的,能执行一定功能的一个过程)

就拿上面设置的信号量empty来举例吧
(1)empty减1;
(2)若empty减1后仍大于或等于零,则进程继续执行;
(3)若empty减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。

上面的运行原语就是P操作了。

V操作:V操作就是对资源的释放

V操作的原语动作如下:

(1)empty加1;
(2)若相加结果大于零,则进程继续执行;
(3)若相加结果小于或等于零(表明有进程阻塞在该类资源上),则从该信号的等待队列中唤醒一等待进程(从阻塞队列里唤醒一个进程来“转手”该类资源,唤醒了就意味着可以干活了),然后再返回原进程继续执行或转进程调度。
注意:PV操作对于每一个进程来说,都只能进行一次,而且必须成对使用。在PV原语执行期间不允许有中断的发生。

PV原语的执行顺序:

先是P操作申请资源empty+1

然后访问临界资源,进行相关操作

然后V操作释放资源empty-1

好的,现在知道啦这些PV操作的原语了。

怎么用PV操作解决消费者生产者之间同步互斥问题?

先放个图:

先声明这两个代码是同时运行的。

分析:这里设置的信号量在声明一些,empty代表空缓冲区的个数设置为n(就是缓冲区还有n个位置),信号量full就是满缓冲区的个数初始为0(也就是占了多少缓冲区)。互斥信号量mutex的初始值为1,在最开始我介绍了为什么要设置互斥。

过程分析

生产者生产产品---->P操作若empty>0则申请资源(申请到一个资源)所以empty-1---->P(mutex)这里初始值为1,执行mutex-1变为了0,好!现在临界资源(缓冲区)只允许生产者一个人使用了,在临界资源上进行相关操作,为什么这里可以实现互斥呢?由于mutex是samephorel变量,所以消费者运行时mutex的值现在是0,所以在消费者的P(mutex)这一步时,进入了阻塞状态,只有等待生产者执行V(mutex)时释放临界资源mutex+1=1,此时的消费者阻塞状态变为执行状态。---->利用临界资源进行相关操作(这里是插入缓冲区)---->执行V(full)操作释放资源full+1(就是将产品放入了仓库),看到上图中的箭头了没有,此时full=1,便可以唤醒消费者进行P(full)操作。---->操作完之后当然要释放临界资源(缓冲区)V(mutex)。---->消费者这边的也是雷同的。

有上面我的解释,可以得出红色箭头中的P(mutex)就是防止消费者也利用临界资源,导致最后的结果错误。

OK!这些操作就可以解决同步互斥问题了,这里要注意的是P(empty)和P(mutex)的顺序问题:都是先执行P(mutex)再进行P(empty),我上面分析了这么多,应该也知道为什么了吧,可以自己分析一下,如果顺序反了,会进入死锁状态。

还有一个问题要注意的就是PV操作是成对出现的。

了解这些后,可以看个经典题目:

桌子上有一空盘,最多允许存放一只水果。爸爸可想盘中放一个苹果或橘子,儿子专等吃盘中的橘子,女儿专等吃苹果。试用wait、signal操作实现爸爸、儿子、女儿三个并发进程的同步。

这里只做简单分析:临界资源是盘子,可设置互斥信号量mutex解决(如果不解决会出现一个盘子有两个水果的情况),设置信号量empty=1,orange=0,apple=0,来解决同步问题

我的答案:

semaphore empty=1,nutex=1,apple=0,orange=0;  //为四个信号量赋初值
void father(){
    while(true){  wait(empty);    //等待盘子为空
           wait(metux);    //等待获取对盘子的操作
            爸爸向盘中放一个苹果;
           signal(mutex);   //释放对盘子的操作
           signal(apple);   //通知女儿可以来盘子中取苹果
    }
}
void father(){               //与父亲进程雷同
     do{
           wait(empty);
           wait(metux);
           爸爸向盘中放一个桔子;
           signal(mutex);
           signal(orange);
    }while(TRUE);
}
void son(){                        
     do{
           wait(orange);       //判断盘子中是否有桔子
           wait(metux);        //等待获取对盘子的操作
            儿子取出盘中的桔子;
           signal(mutex);      //释放对盘子的操作
           signal(empty);      //盘子空了,可以继续放水果了
    }while(TRUE);
}
void daugther(){               //与儿子进程雷同
     do{
           wait(apple);
           wait(metux);
            女儿取出盘中的苹果;
           signal(mutex);
           signal(empty);
    }while(TRUE);
}
void main() {               //四个并发进程的同步执行
	cobegin
	   father();mather();son();daugther();
	coend
}

上面的这个金典问题也很好的将PV操作解决同步互斥问题展现的淋漓尽致!

还有一个重要的点忘说了,那就是wait、和signal的操作与PV操作的区别,这里你可以理解为wait操作就是P操作,用来申请资源的,signal操作就是V操作用来释放资源的。

上面的分析不知道有没有错误,望发现错误的大神指明我的错误!!

发布了23 篇原创文章 · 获赞 21 · 访问量 5169

猜你喜欢

转载自blog.csdn.net/LTtiandd/article/details/104826908