二元信号量一个小例子

本文介绍了在学习操作系统过程中遇到的一个关于二元信号量的生产者消费者问题。问题在于信号量使用不当导致产品被过度消费,分析了错误原因并提出解决方案。作者还提出了一个疑问,探讨是否可以不加条件地每次生产后就发送信号给消费者。

引言

这偏文章主要是在我学习操作系统的时候遇到书上的一个关于信号量的例题,而自己在复习的时候依然卡在这个问题上好长时间,因此特别将这个问题写出,以防下次还忘记,例子比较简单,也欢迎大家发表自己的看法。

生产者消费者问题-(《操作系统-精髓与设计原理》第八版-p143页,图5.9)

/*program producerconsumer */
    int n;
    binary_semaphore s=1,dalay=0;
    void producer(){
        while(true){
            produce();
            semwaitB(s);
            append();
            n++;
            if(n==1)semSignalB(delay);
            semSignalB(s);
        }
    }
    void consumer(){
        semWaitB(delay);
        while(true){
            semWaitB(s);
            take();
            n--;
            semSignalB(s);
            consume();
            if(n==0)semWaitB(delay);
        }
    }
    void main(){
        n=0;
        parbegin(producer,consumer);
    }
  • 生产者消费者问题,主要是通过生产者生产出产品放入缓冲区,然后消费者从缓冲区中拿出产品消费。

  • 生产者和消费者不能同时在临界区进行操作,同一时间只能有一个生产者或者一个消费者在临界区进行操作。


  • 其中信号量s控制临界区是否上锁。信号量delay的作用是当缓冲区没有可消费物品时,阻塞消费者。两个信号量都是二元信号量
  • delay的初始值为0,在生产者中 if(n==1)semSignalB(delay)语句的目的是在生产者将生产出的产品放入缓冲区后,delay的值变为1,给消费者发信号,告诉消费者可以消费了。此时阻塞在semWaitB(delay)上的一个消费者进入就绪队列准备消费。当消费者发现缓冲区已经没有产品时,将自身阻塞,即if(n==0)semWaitB(delay)语句的作用.
  • 但是当前的程序有问题,问题如下表
序号生产者消费者sndelay
1101
2semwaitB(s);100
3n++;010
4if(n==1)semSignalB(delay);011
5semSignalB(s);111
6semWaitB(delay);110
7semWaitB(s);010
8n–;000
9semSignalB(s);100
10semwaitB(s);000
11n++;010
12if(n==1)semSignalB(delay);011
13semSignalB(s);111
14if(n==0)semWaitB(delay);111
15semWaitB(s);011
16n–;001
17semSignalB(s)101
18if(n==0)semWaitB(delay);100
19semWaitB(s);000
20n–;0-10
21semSignalB(s)1-10

- 在第8行,此时产品被消费掉,n=0,此时应执行if(n==0)semWaitB(delay);,将进程本身阻塞,而此时生产者在第10行进入临界区,并将delay的值重新置为1,又生产了一个产品。此时再第14行执行if(n==0)semWaitB(delay)时并未生效,而是继续执行,在18行将delay置零,但是并未阻塞,于是又进行了一轮运行,最终得到n=-1,表示消费了还没有生产出的产品,显然这是错误的。产生这一错误的主要原因是执行顺序颠倒,应该先执行if(n==0)semWaitB(delay);,再执行生产者临界区。

解决方法:我曾经想过将if(n==0)semWaitB(delay)语句移入临界区执行,但是这一方法会产生死锁,因为还未退出临界区就将自己阻塞了。实际的解决方法应该是引入一个辅助变量,解决代码如下

/*program producerconsumer */
    int n;
    binary_semaphore s=1,dalay=0;
    void producer(){
        while(true){
            produce();
            semwaitB(s);
            append();
            n++;
            if(n==1)semSignalB(delay);
            semSignalB(s);
        }
    }
    void consumer(){
        int m;//引入辅助变量
        semWaitB(delay);
        while(true){
            semWaitB(s);
            take();
            n--;
            m=n;
            semSignalB(s);
            consume();
            if(m==0)semWaitB(delay);//使用辅助变量完成执行
        }
    }
    void main(){
        n=0;
        parbegin(producer,consumer);
    }

结尾

写完这个博客,我有一个小问题,在生产者进程中,如果将“if(n==1)semSignalB(delay);”这个语句中的if(n==1)去掉,即每次只要一有生产者写入缓冲区,就发送semSignal信号是否可以呢?
我个人认为是可以的,欢迎在评论中回复我。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值