生产者消费者 & 读者写者

生产者消费者

对于生产者消费者这个问题,我们可以用生活中一个简单的例子来说明:

桌子上有个盘子,一个人往盘子里面放苹果,一个人从盘子里面拿走苹果,放苹果的人相当于生产者,拿走苹果的人相当于消费者,而盘子就相当于一个生产场所。如果我们要保证拿苹果的人一直都有苹果拿,那就要让放苹果的人一直放,而且要比拿苹果的人快一点。当盘子满的时候放苹果的人就要等着拿苹果的人把苹果拿走,等盘子里有了位置,就可以继续放苹果。如果我们要求每次只能放一个苹果,拿苹果的人每次也只能拿一个苹果,而放苹果和拿苹果的人都不只是一个人,这样的话,放苹果的人和放苹果的人之间就会产生互斥关系,一个人放苹果的时候,其他人就不能放,拿苹果的人也是一样,一个人拿苹果的时候,其他人就不能拿。而拿苹果的人和放苹果的人也有互斥关系和同步关系,放苹果的人放了苹果之后,要通知拿苹果的人来拿苹果,否则盘子满了,放苹果的人就要等待。

好了,不说苹果了,我们来官方一点啦

生产者要做的就是生产数据,消费者要做的是读取数据并且要拿走。而且生产者和消费者是在一个环形缓冲区进行的,和我在管道那篇博客中写的一样

生产者消费者之间的关系

(1)消费者和消费者是互斥关系,因为一个消费者来读取数据的时候其他消费者是不能来读取数据的

(2)生产者和生产者是互斥关系,因为一个生产者在写入数据的时候其他生产者是不能写入数据的

(3)生产者和消费者是互斥关系,同步关系,当生产者生产了之后,会通知消费者来消费,否则当生产者生产满了的时候,就需要等待消费者来消费,等到满足生产的要求的时候再生产,这就对于临界资源的访问会产生一定的顺序,会提高系统内部资源的读取速度。

消费者指向的位置都是有有效数据的,生产者指向的位置都是没有有效数据的,和管道的环形缓冲区类似,把管道的环形缓冲区图拿过来凑合看看理解吧。这幅图里面,你可以把write看作是生产者,在一直生产数据,read可以看作是消费者,一直在读取数据。生产者所关心的资源是环形buf中空余的位置,即没有有效数据的位置,消费者不关心格子,只关心数据

读者写者问题

读者写者都干什么呢?

写者把数据扔到缓冲区中,读者只读数据,不会把数据拿走

读者写者的关系:

(1)读者和读者没有关系,因为数据不会被拿走,不会发生争夺资源的问题,所以谁都可以读到相同的数据,

(2)写者和写者是互斥关系,一个写的时候其他写者就不能写

(3)读者和写者是互斥关系,同步关系,类似生产者和消费者

读者写者会出现的问题:

(1)读者很多,写者只有一个的时候,读者会不断的来读数据,写者没机会写如数据,则会出现写者饥饿

(2)写者很多,读者只有一个的时候,写者会不断的写入数据,读者没机会写入数据,则会出现读者饥饿

针对写者饥饿和读者饥饿的解决方法:

(1)写者优先:当有很多读者的时候,当写者来的时候,后续来的读者就不能读了,等当前正在读的读者读完,然后让写者先写,其他读者不能进行读取

(2)读者优先:当有很多写者,来了一个读者的时候,当当前写者写完的时候让读者先读,读完了再让其他的写者写

关于读写锁:

(1)以只读方式加锁,是读者的行为,当有写者的时候,写者不会进行写操作,写者检测到读者有读锁的时候(Pthread_rwlock_tryrdlock(&rwlock)!=0) 会等待,直到读者不再读,如果没有检测到只读锁(Pthread_rwlock_tryrdlock(&rwlock)==0),则会直接写入

(2)其他锁是基于挂起,当申请锁的时候申请不到就会被挂起等待其他进程释放锁

(3)读写锁是基于自旋锁,申请锁资源,如果锁资源就绪,就会立即被占用,如果锁资源没有就绪,则会一直自旋申请

自旋锁:当申请资源的时候不会被挂起,节省了挂起和唤醒的代价

如果在临界资源里逗留的时间很长,则需要使用互斥锁或者信号量

时间: 2024-10-16 04:57:31

生产者消费者 & 读者写者的相关文章

Java实现生产者消费者问题与读者写者问题

摘要: Java实现生产者消费者问题与读者写者问题 1.生产者消费者问题 生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品.解决生产者/消费者问题的方法可分为两类:(1)采用某种机制保护生产者和消费者之间的同步:(2)在生产者和消费者之间建立一个管道.第一种方式有较高的效率,并且易于实现,代码的可控制性较好,属于常用的模式.第二种管道缓冲区不易控制,被传输数据对象不易于封装等,实用性不强. 同步问题核心在

‘生产者-消费者’模型与‘读-写者’模型

★生产者-消费者模型 首先,我们先分析一下生产者与消费者模型:生产者与消费者是模型中不可缺少的2种角色,当然模型中肯定需要一个保存数据的场所,能够将生产者生产的数据进行存储.同时,模型必须要满足生产者产生出数据后,消费者才能够进行使用,即就是消费者必须位于生产者之后,当然生产者生产的数据最多将场所放置满就不能继续生产,下面有简单的图示: 当然,如果有多个消费者和多个生产者,生产者与消费者之间的关系是同步的,生产者与生产者之间是互斥的,因为一块空间不能让多个生产者同时进行生产.消费者和消费者之间也

利用生产者消费者模型和MQ模型写一个自己的日志系统-并发设计里一定会用到的手段

一:前言 写这个程序主要是用来理解生产者消费者模型,以及通过这个Demo来理解Redis的单线程取原子任务是怎么实现的和巩固一下并发相关的知识:这个虽然是个Demo,但是只要稍加改下Appender部分也是可以用于项目中的,假设项目里确实不需要log4j/logback之类的日志组件的时候: 二:实现方式 1.利用LinkedList作为MQ(还可以用jdk自带的LinkedBlockingQueue,不过这个Demo主要是为了更好的理解原理因此写的比较底层): 2.利用一个Daemon线程作为

用yield写协程实现生产者消费者

思路: yield可以使得函数阻塞,next,和send可以解阻塞,实现数据不竞争的生产者消费者模式 代码: import random #随机数,模拟生产者的制造物 def eat(): #消费者 while True: item = (yield) print("消费了:",item) def pro(g): #生产者 next(g) while True: item = random.randint(0,99) print("生产了:",item) g.sen

利用JAVA线程安全队列简单实现读者写者问题。

常见的操作系统教科书中,会使用互斥锁来实现读者线程和写者线程的同步问题,但是在JDK5推出线程安全队列之后,将该问题变得异常简单. java.util.concurrent.ConcurrentLinkedQueue 是线程安全的非阻塞队列,其实很容易想到,非阻塞队列当线程需要等待的时候,则不会阻塞等待,而是直接根据情况返回. java.util.concurrent.LinkedBlockingQueue 是线程安全的阻塞队列,该队列能够在很多情况下对线程进行阻塞,比如队列为空时调用take(

秒杀多线程第十一篇 读者写者问题

与上一篇<秒杀多线程第十篇 生产者消费者问题>的生产者消费者问题一样,读者写者也是一个非常著名的同步问题.读者写者问题描述非常简单,有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者在读文件时写者也不去能写文件. 上面是读者写者问题示意图,类似于生产者消费者问题的分析过程,首先来找找哪些是属于“等待”情况. 第一.写者要等到没有读者时才能去写文件. 第二.所有读者要等待写者完成写文件后才能去读文件. 找完“等待”情况后,再看看有没有要互斥访问的资源.由

【操作系统】经典的同步问题(生产者消费者问题, 哲学家进餐问题, 读写问题)

用专业术语来说, 进程是程序的一次动态执行.说简单点, 就是进程是系统中的某个任务.操作系统中有多个任务需要执行, 那么怎样执行才能使它们同步呢? 即如何让任务并发执行互不影响呢? 这就引出了进程同步中的经典问题: 生产者消费者问题, 哲学家进餐问题, 读写问题 生产者-消费者问题 有一群生产者进程在生产产品, 并将这些产品提供给消费者进程取消费. 为使生产者进程与消费者进程能并发进行, 在两者间设置了一个具有n个缓冲区的缓冲池, 生产者进程将其所生产的产品翻入缓冲区中, 消费者进程可从一个缓冲

生产者消费者问题、Java实现

来,今天尝试把这个问题搞定.还是这种节奏,看一个问题要先从历史看.全局看,这样我们才能真正掌握其全貌,最终各个击破,了然于胸! 我们先来温习下如下概念: 1. 基础概念 基本的 程序 - Program 程序是静态的源代码或目标程序,是一个没有生命的实体. 进程 - Process 当CPU赋予程序生命时也即操作系统执行它时,程序成为了一个活动的实体(但不是可执行的实体),称为进程 - 进行中的程序. 进程是程序的一个实例: 是计算机分配资源的基本单位: 是线程的容器: 线程 - Thread

用信号量和读写锁解决读者写者问题

读者写者问题是非常经典的同步问题,本文首先用信号量来解决这个问题,并结合代码分析什么是读者优先.什么是写者优先,然后给出读写锁的解决方案,并指出在Linux下读写锁的注意事项. 读者写者问题 读者写者问题描述的是这么一种情况:对象在多个线程(或者进程)之间共享,其中一些线程只会读数据,另外一些线程只会写数据.为了保证写入和读取的正确性,我们需要保证,只要有线程在写,那么其他线程不能读,否则可能读到写了一半的数据:另外,也不能有两个线程同时写,否则导致数据错乱.当然,多个线程是可以同时读数据. 读