生产者消费者问题

1. 问题定义
某些进程生产数据,另一些进程消费数据,他们之间通过一个大小为N的先入先出队列来进行数据的传递。
当队列是满的时候,生产者阻塞,当队列是空的时候,消费者阻塞。
这种场景还是挺常见的,比如媒体流的处理。
2. PV原语
PV原语,这个概念的提出者是河南(荷兰)科学家Dijkstra,这位爷也提出了图的Dijkstra最短路径算法。原语的意思是atomic操作,就是无法分割,不可打断的操作。PV原语是用来操作信号量的,笼统的说,P操作减少信号量,V操作增加信号量,精确的说,请看伪代码:
procedure P(var s:samephore);
{
     s.value=s.value-1;
     if (s.value<0) asleep(s.queue);
}
procedure V(var s:samephore);
{
     s.value=s.value+1;
     if (s.value<=0) wakeup(s.queue);
}


这里的s是信号量(samephore ),s.queue是指s的阻塞进程队列,这也是一个先入先出队列。asleep(s.queue)意味着把本进程放入队列,wakeup(s.queue)意味着把位于队列头的一个进程唤醒,所谓唤醒,也就是放入操作系统的就绪队列。
3. 解决问题
生产者消费者问题的完美解决需要三个信号量:fullCount,emptyCount和useQueue。顾名思义,fullCount意味着队列中元素的个数,emptyCount意味着队列中空位的个数,useQueue意味着当前是不是有进程在访问队列。在跑起来的时候,emptyCount是会小于队列中空位的个数的,比如当很多生产者同时等待useQueue时;同理,fullCount也是会小于队列中元素的个数的,比如很多消费者同时等待useQueue时------好像东西还在你的仓库里,而你已经把它预售出去了一样。所以fullCount+emptyCount <= N,但是,当生产者进程和消费者进程都只有一个的情况下,fullCount+emptyCount == N。
注意,这里的useQueue是个取值为0或1的信号量,也叫互斥型信号量,即mutex。
初始化fullCount.value为0,emptyCount.value 为N,useQueue.value为1,那么:
produce:
    P(emptyCount)
    P(useQueue)
    putItemIntoQueue(item)
    V(useQueue)
    V(fullCount)
consume:
    P(fullCount)
    P(useQueue)
    item ← getItemFromQueue()
    V(useQueue)
    V(emptyCount)


4. 例子
Android中AudioTrack和AudioFlinger的数据交换是个简化版的生产者消费者问题,说它简化,是因为首先生产者,消费者都只有一个,其次共享数据的只有一个Buffer,也就是说队列的N==1,每次生产者都努力把Buffer填满,消费者都努力把Buffer消费干净。
所以,仅仅需要一个useQueue 就能满足需求了!
这个信号量在 audio_track_cblk_t  中定义,这是一个环形Buffer,循环的写和读,顺便说一句,环形buffer关键就是记录要读和写的位置,根据这些,也可以得到buffer是空还是满。
在audio_track_cblk_t 中,有一个volatile int32_tmFutex, 这个是生产者消费者PV操作的关键,代码中注释是:event flag: down (P) by client, up (V) by server or binderDied() or interrupt()。 相应的PV操作是__futex_syscall4,类似于Wait,还有__futex_syscall3,类似于Signal。这俩实现了对进程的阻塞和唤醒。
在这个简化的模型中,AudioTrack是生产者,它每次都写满buffer,然后sleep,并wakeup消费者;AudioFlinger是消费者,它每次都读空buffer,然后sleep,并wakeup生产者。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值