之前介绍的几种解决进程间互斥的方案,不管是Peterson方案还是TSL指令的方式,都有一个特点:当一个进程被Block到临界区外面时,被Block的进程会一直处于忙等待的状态,这个不但浪费了CPU资源,还会有一个很坏的副作用。假设两个进程,H,L,H的优先级高,L进程的优先级非常低,CPU的调度规则是只要H处于Ready状态,则开始运行H,问题来了:

  • H处于BLock状态,可能在等待外部资源
  • L进入了临界区
  • H处于Ready状态(外部资源满足),L还没有离开临界区
  • 按照调度规则,CPU会Switch到H,L会挂起。
  • H开始运行,但是由于L在临界区,这个时候H会处于无限循环,一直处于临界区外面等待。
  • L也将永远无法离开临界区

一、生产者消费者引入

1.1 解决无限等待问题

如果一个进程不容许进入临界区时,这个时候让这个进程block,则解决了无线等待问题,文章开头提出的问题也就解决了。怎么block进程。

  1. 通过系统调用sleep,则可以让进程处于block状态。
  2. 被sleep的进程会一直挂起直到被调用wakeup

示意图:

生产者消费者主要是当往Buffer插入数据的时候发现buffer已经满了,则让生产者sleep,而是不无限循环等待

当发现buffer没有数据的时候让消费者sleep,而不是无限循环等待。

当buffer有数据时候,但是发现之前消费者属于sleep状态,则让消费者wakeup。

当buffer没有数据时候,但是发现之前生产者处于sleep状态,则让生产者wakeup。

1.2 代码演示

#definne N   //buffer 的容量
int count = ; //buffer中item的数量 void producer(void)
{
int item;
while(true)//永远执行
{
item= produce_item();//生成下一个item
   if(count == N)//如果buffer已经满了,则sleep
{
sleep();
}
insert_item(item);//将item放入buffer
   count = count + ;//数量+1
   if(count == )//之前buffer是空的,所以consumer处于sleep状态,现在有item了,唤醒consumer
{
wakeup(consumer);
}
}
} void consumer(void)
{
int item;
while(true)
{
if(count == )//如果buffer是空的,则sleep
{
sleep();
}
item = remove_item();//将item从buffer移除
  count = count - ;//数量-1
  if(count == N - )//之前buffer已经满了,所以producer处于sleep状态,现在移除了一个item,唤醒producer
{
wakeup(producer);
}
consume_item(item);//消费item
}
}

二、生产者消费者的条件竞争问题

上面的代码依然存在竞争条件问题(Race Conditions),考虑如下情况:

  1. buffer是空的,消费者刚刚读取到count,要去判断count是不是0,还没有走到sleep
  2. scheduler决定暂时停止消费者,让CPU去运行生产者
  3. 生产者如程序所示,会在buffer中增加一个item
  4. 因为之前count是你0,所以消费者认为consumer应该是sleep状态
  5. 发送wakeup(consumer)指令

以上完成后,由于之前的消费者因为cpu的调度没有走到sleep状态,所以wakeup对消费者是不起作用的。所以wakeup的信号就丢失了。

继续:

  1. cpu决定运行消费者,这个时候会从之前暂停的地方开始,count==0成立,consumer会进入sleep状态
  2. 接下来当生产者开始运行的时候,因为count已经是1了,所以永远都不会在运行wakeup(消费者)

最终结果:

  1. 生产者把buffer插满
  2. 消费者永远处于sleep状态

上面问题的关键是wakeup指令发给了一个没有sleep的进程,wakeup不起作用,wakeup的型号最终丢失了。

一个快速的解决方案是给进程加一个Wakeup waiting Bit,当一个wakeup请求发给一个处于wakeup的进程时,将这个进程的Wakeup waiting Bit标志位设置为true。接下来当有sleep给这个进程时,判断一下如果Wakeup waiting Bit为true,则不sleep。

这个方法能暂时解决问题,但是很糟糕,如果有多个进程时,就需要很多标志位。接下来几篇文章会专门将信号量,互斥体等来解决生产者消费者的竞争条件问题。

Operating System-进程间互斥的问题-生产者&&消费者引入的更多相关文章

  1. Operating System-进程间互斥的方案-保证同一时间只有一个进程进入临界区(3)- TSL指令

    本文接上一篇文章继续介绍如何实现同一时间只允许一个进程进入临界区的机制.本文主要介绍TSL指令. 方案汇总 屏蔽中断 锁变量 严格轮换法 TSL指令 Peterson解法 一.What is TSL ...

  2. pthread mutex 进程间互斥锁实例

    共享标志 定义 名称 描述 0 PTHREAD_PROCESS_PRIVATE 进程内互斥锁 仅可当前进程内共享 1 PTHREAD_PROCESS_SHARED 进程间互斥锁 多个进程间共享 第一个 ...

  3. POSIX信号量与互斥锁实现生产者消费者模型

    posix信号量 Link with -lpthread. sem_t *sem_open(const char *name, int oflag);//打开POSIX信号量 sem_t *sem_o ...

  4. python并发编程之守护进程、互斥锁以及生产者和消费者模型

    一.守护进程 主进程创建守护进程 守护进程其实就是'子进程' 一.守护进程内无法在开启子进程,否则会报错二.进程之间代码是相互独立的,主进程代码运行完毕,守护进程也会随机结束 守护进程简单实例: fr ...

  5. Mutex 进程间互斥

    学习Mutex的心得,不一定对,先记录一下. 同步技术分为两大类,锁定和信号同步. 锁定分为:Lock.Monitor 信号同步分为:AutoResetEvent.ManualResetEvent.S ...

  6. Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

    Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post ...

  7. posix 匿名信号量与互斥锁 示例生产者--消费者问题

    一.posix 信号量 信号量的概念参见这里.前面也讲过system v 信号量,现在来说说posix 信号量. system v 信号量只能用于进程间同步,而posix 信号量除了可以进程间同步,还 ...

  8. 进程同步控制(锁,信号量,事件), 进程通讯(队列和管道,生产者消费者模型) 数据共享(进程池和mutiprocess.Pool模块)

    参考博客 https://www.cnblogs.com/xiao987334176/p/9025072.html#autoid-1-1-0 进程同步(multiprocess.Lock.Semaph ...

  9. 网络编程基础----并发编程 ---守护进程----同步锁 lock-----IPC机制----生产者消费者模型

    1  守护进程: 主进程 创建 守护进程   辅助主进程的运行 设置进程的 daemon属性 p1.daemon=True 1 守护进程会在主进程代码执行结束后就终止: 2 守护进程内无法再开启子进程 ...

随机推荐

  1. 快乐学习 Ionic Framework+PhoneGap 手册1-3 {面板切换}

    编程的快乐和乐趣,来自于能成功运行程序并运用到项目中,会在后面案例,实际运用到项目当中与数据更新一起说明 从面板切换开始,请看效果图和代码,这只是一个面板切换的效果 Index HTML Code & ...

  2. 20145240 《Java程序设计》第六周学习总结

    20145240 <Java程序设计>第六周学习总结 教材学习内容总结 InputStream与OutputStream 10.1.1串流设计的概念 Java将输入/输出抽象化为串流,数据 ...

  3. Kubernetes lxcfs

    容器实现的基础是NameSpace和Cgroups. NameSpace实现了对容器(进程)的隔离,NameSpace技术实际上修改了应用进程看待整个计算机“视图”,也就是作用域,即它的“视线”被操作 ...

  4. python基础语法学习常见小问题

    说明:我是最近觉得python在完成很多工作中方便使用而且功能强大,想突击学习一下.用的是廖雪峰老师的教程,学习python3.X.这里是廖雪峰老师的网站链接: http://www.liaoxuef ...

  5. 【P2016】战略游戏(贪心||树状DP)

    这个题真是...看了一会之后,发现有一丝丝的熟悉,再仔细看了看,R,这不是那个将军令么...然后果断调出来那个题,还真是,而且貌似还是简化版的...于是就直接改了改建树和输入输出直接交了..阿勒,就2 ...

  6. 【bzoj2423】最长公共子序列[HAOI2010](dp)

    题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2423 题目大意:求两个字符串的最长公共子序列长度和最长公共子序列个数. 这道题的话,对于 ...

  7. 分析新建的android代码

    1).xml文件中的<?xml version="1.0" encoding="utf-8"?>是每个xml文件开仅有一个的声明xml的代码. 2) ...

  8. asp.net 锚点

    可以使用锚点,但这里可使用灵活处理 首先获取需要滚动到的位置的id,如,可以设置一个元素(,注:要在form里),另外在form的任意位置设置 代码如下: 注:a标签里不要有内容,在回传的地方调用 代 ...

  9. JSON 在JavaScript 中的应用及自己的理解

    [对象和json]JSON:JavaScript 对象表示法(JavaScript Object Notation).JSON 是存储和交换文本信息的语法.类似 XML.JSON是一种数据格式,不是一 ...

  10. EDID真实数据块,请参考标准文档仔细核对

    数据格式的详细说明:http://en.wikipedia.org/wiki/Extended_display_identification_data 下面是一个例子: