用多线程同步方法解决生产者-消费者问题操作系统课设
生产者消费者程序设计

生产者消费者程序设计在计算机科学中,生产者消费者问题是一个经典的多线程同步问题,它反映了在并发环境中生产者和消费者之间的协作关系。
这个问题不仅在理论上具有重要意义,而且在实际的软件开发中也有广泛的应用。
让我们先来理解一下什么是生产者和消费者。
简单来说,生产者就是负责生产数据或产品的部分,而消费者则是使用或消耗这些数据或产品的部分。
想象一个面包店的场景。
面包师傅(生产者)不断地制作面包,然后将它们放在货架上。
顾客(消费者)则从货架上购买并享用这些面包。
在这个过程中,如果面包师傅制作面包的速度太快,货架放不下,就会出现问题;如果制作速度太慢,顾客可能会等得不耐烦。
同样,如果顾客购买面包的速度太快,面包师傅来不及制作,顾客会感到不满;如果购买速度太慢,面包可能会过期。
在程序设计中,我们要解决的就是如何让生产者和消费者能够高效、协调地工作,避免出现上述的问题。
为了实现生产者消费者的有效协作,我们通常会使用一些同步机制。
其中,最常见的就是使用缓冲区。
缓冲区就像是面包店中的货架,生产者将生产出来的数据放入缓冲区,消费者从缓冲区中取出数据进行处理。
在实现生产者消费者程序时,我们需要考虑几个关键的要点。
首先是线程安全。
由于生产者和消费者是在不同的线程中运行的,可能会同时访问缓冲区,这就可能导致数据不一致或者竞争条件等问题。
为了解决这个问题,我们通常会使用锁或者信号量等机制来保证线程安全。
例如,我们可以使用一个互斥锁来保护缓冲区的访问。
当生产者想要向缓冲区中添加数据时,它首先需要获取锁,添加完成后释放锁。
消费者在从缓冲区中取出数据时,也需要先获取锁,取出后释放锁。
这样就可以确保在同一时间只有一个线程能够访问缓冲区,避免了数据冲突。
其次是缓冲区的设计。
缓冲区的大小是一个需要仔细考虑的因素。
如果缓冲区太小,生产者可能会经常因为缓冲区已满而等待;如果缓冲区太大,会浪费内存资源。
一般来说,缓冲区的大小需要根据生产者和消费者的生产和消费速度来确定。
C++11并发指南九(综合运用:C++11多线程下生产者消费者模型详解)

C++11并发指南九(综合运⽤:C++11多线程下⽣产者消费者模型详解)前⾯⼋章介绍了 C++11 并发编程的基础(抱歉哈,第五章-第⼋章还在草稿中),本⽂将综合运⽤ C++11 中的新的基础设施(主要是多线程、锁、条件变量)来阐述⼀个经典问题——,并给出完整的解决⽅案。
⽣产者消费者问题是多线程并发中⼀个⾮常经典的问题,相信学过操作系统课程的同学都清楚这个问题的根源。
本⽂将就四种情况分析并介绍⽣产者和消费者问题,它们分别是:单⽣产者-单消费者模型,单⽣产者-多消费者模型,多⽣产者-单消费者模型,多⽣产者-多消费者模型,我会给出四种情况下的 C++11 并发解决⽅案,如果⽂中出现了错误或者你对代码有异议,欢迎交流 ;-)。
单⽣产者-单消费者模型顾名思义,单⽣产者-单消费者模型中只有⼀个⽣产者和⼀个消费者,⽣产者不停地往产品库中放⼊产品,消费者则从产品库中取⾛产品,产品库容积有限制,只能容纳⼀定数⽬的产品,如果⽣产者⽣产产品的速度过快,则需要等待消费者取⾛产品之后,产品库不为空才能继续往产品库中放置新的产品,相反,如果消费者取⾛产品的速度过快,则可能⾯临产品库中没有产品可使⽤的情况,此时需要等待⽣产者放⼊⼀个产品后,消费者才能继续⼯作。
C++11实现单⽣产者单消费者模型的代码如下:#include <unistd.h>#include <cstdlib>#include <condition_variable>#include <iostream>#include <mutex>#include <thread>static const int kItemRepositorySize = 10; // Item buffer size.static const int kItemsToProduce = 1000; // How many items we plan to produce.struct ItemRepository {int item_buffer[kItemRepositorySize]; // 产品缓冲区, 配合 read_position 和 write_position 模型环形队列.size_t read_position; // 消费者读取产品位置.size_t write_position; // ⽣产者写⼊产品位置.std::mutex mtx; // 互斥量,保护产品缓冲区std::condition_variable repo_not_full; // 条件变量, 指⽰产品缓冲区不为满.std::condition_variable repo_not_empty; // 条件变量, 指⽰产品缓冲区不为空.} gItemRepository; // 产品库全局变量, ⽣产者和消费者操作该变量.typedef struct ItemRepository ItemRepository;void ProduceItem(ItemRepository *ir, int item){std::unique_lock<std::mutex> lock(ir->mtx);while(((ir->write_position + 1) % kItemRepositorySize)== ir->read_position) { // item buffer is full, just wait here.std::cout << "Producer is waiting for an empty slot...\n";(ir->repo_not_full).wait(lock); // ⽣产者等待"产品库缓冲区不为满"这⼀条件发⽣.}(ir->item_buffer)[ir->write_position] = item; // 写⼊产品.(ir->write_position)++; // 写⼊位置后移.if (ir->write_position == kItemRepositorySize) // 写⼊位置若是在队列最后则重新设置为初始位置.ir->write_position = 0;(ir->repo_not_empty).notify_all(); // 通知消费者产品库不为空.lock.unlock(); // 解锁.}int ConsumeItem(ItemRepository *ir){int data;std::unique_lock<std::mutex> lock(ir->mtx);// item buffer is empty, just wait here.while(ir->write_position == ir->read_position) {std::cout << "Consumer is waiting for items...\n";(ir->repo_not_empty).wait(lock); // 消费者等待"产品库缓冲区不为空"这⼀条件发⽣.}data = (ir->item_buffer)[ir->read_position]; // 读取某⼀产品(ir->read_position)++; // 读取位置后移if (ir->read_position >= kItemRepositorySize) // 读取位置若移到最后,则重新置位.ir->read_position = 0;(ir->repo_not_full).notify_all(); // 通知消费者产品库不为满.lock.unlock(); // 解锁.return data; // 返回产品.}void ProducerTask() // ⽣产者任务{for (int i = 1; i <= kItemsToProduce; ++i) {// sleep(1);std::cout << "Produce the " << i << "^th item..." << std::endl;ProduceItem(&gItemRepository, i); // 循环⽣产 kItemsToProduce 个产品.}}void ConsumerTask() // 消费者任务{static int cnt = 0;while(1) {sleep(1);int item = ConsumeItem(&gItemRepository); // 消费⼀个产品.std::cout << "Consume the " << item << "^th item" << std::endl;if (++cnt == kItemsToProduce) break; // 如果产品消费个数为 kItemsToProduce, 则退出.}}void InitItemRepository(ItemRepository *ir){ir->write_position = 0; // 初始化产品写⼊位置.ir->read_position = 0; // 初始化产品读取位置.}int main(){InitItemRepository(&gItemRepository);std::thread producer(ProducerTask); // 创建⽣产者线程.std::thread consumer(ConsumerTask); // 创建消费之线程.producer.join();consumer.join();}单⽣产者-多消费者模型与单⽣产者和单消费者模型不同的是,单⽣产者-多消费者模型中可以允许多个消费者同时从产品库中取⾛产品。
操作系统课程设计——生产者消费者问题

计算机与信息学院《操作系统与编译原理联合课程设计报告》专题:操作系统部分学生姓名:学号:专业班级:指导教师:2014 年 7 月一、设计目标多进程/线程编程:生产者-消费者问题。
设置两类进程/线程,一类为生产者,一类为消费者;建立缓冲区的数据结构;随机启动生产者或消费者;显示缓冲区状况;随着进程/线程每次操作缓冲区,更新显示。
二、设计思路1.开发平台:Visual C++6.02.设计思路:若干个生产者和若干个消费者共享一个有界缓冲区,生产者生产产品,消费者消费产品。
消费者进程与生产者进程随机切换。
生产者将产品生产出来后,存放到缓冲区中的空闲位置并将此缓冲区的标识置为满,若此时无空缓冲区,则进行等待。
消费者将标识为满的缓冲区中的产品取出,进行消费并将该缓冲区的标志位置为空,若此时无满的缓冲区,则进行等待。
由于消费者与生产者共享缓冲区资源,且缓冲区资源属于互斥资源,所以生产者和消费者需要按照一定的规则访问缓冲区,访问规则如下:(1)当一个消费者访问缓冲区时其他消费者不允许访问缓冲区,同样的,当一个生产者访问缓冲区时其他生产者也不能访问缓冲区。
(2)当消费者访问缓冲区资源时生产者不能访问,反之,当生产者访问缓冲区资源时消费者不能访问。
(3)当缓冲区中无产品时,消费者不能访问;当缓冲区已满时,生产者不能访问缓冲区。
生产者与消费者问题伪代码如下:VAR mutex, empty, full: semaphore := 1, n, 0 ;in,out: integer := 0, 0 ;Buffer: array [0..n-1] of item ;ParbeginProducer:beginrepeatproduce an item in nextp;wait(empty);wait(mutex);Buffer(in) := nextp;in := (in + 1) mod n;signal(mutex);signal(full);until falseendConsumer:beginrepeatwait(full);wait(mutex);nextc = Buffer(out);out := (out + 1) mod n;signal(mutex);signal(empty);consume the item nextc;until falseendParend程序框架如下图所示:本程序在具体实现方面与MFC结合,将生产者-消费者问题的具体过程动态展示了出来。
【实验】java多线程实验报告

【关键字】实验java多线程实验报告篇一:西北农林科技大学java多线程实验报告实验7 多线程1.实验目的(1) 掌握Java多线程的概念和实现方法(2) 掌握Java多线程的同步问题2.实验内容任务一:火车售票假设有火车票1000张,创建10个线程模拟10个售票点,每个售票点100毫秒买一张票。
打印出售票过程,注意使用synchronized确保同一张票只能卖出一次。
程序运行结果见左图。
打开EclipseTickets.javapublic class Ticket extends Thread {int ticket =1000; String name =""; public void run(){ while(true){synchronized(name){ if(ticket"第" + Thread.currentThread().getName()+ "售票点卖出了第" + ticket-- + "张票");}} }}} try{ } catch(InterruptedException e){ } Thread.sleep(100);Test.javapublic class Test {} public static void main(String args[]){} Ticket t = new Ticket(); new Thread(t,"1").start(); new Thread(t,"2").start(); new Thread(t,"3").start(); new Thread(t,"4").start(); new Thread(t,"5").start(); new Thread(t,"6").start(); new Thread(t,"7").start(); new Thread(t,"8").start(); new Thread(t,"9").start(); new Thread(t,"10").start();任务二:银行存款假设某家银行,它可接受顾客的汇款,每做一次汇款,便可计算出汇款的总额。
操作系统中的经典问题——生产者消费者问题(两种方式实现)

操作系统中的经典问题——⽣产者消费者问题(两种⽅式实现)操作系统中的经典问题——⽣产者消费者问题(两种⽅式实现)1、问题引⼊:什么是⽣产者消费者问题?⽣产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是⼀个多线程同步问题的经典案例。
该问题描述了共享固定⼤⼩缓冲区的两个线程——即所谓的“⽣产者”和“消费者”——在实际运⾏时会发⽣的问题。
⽣产者的主要作⽤是⽣成⼀定量的数据放到缓冲区中,然后重复此过程。
与此同时,消费者也在缓冲区消耗这些数据。
该问题的关键就是要保证⽣产者不会在缓冲区满时加⼊数据,消费者也不会在缓冲区中空时消耗数据。
.要解决该问题,就必须让⽣产者在缓冲区满时休眠(要么⼲脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,⽣产者才能被唤醒,开始往缓冲区添加数据。
同样,也可以让消费者在缓冲区空时进⼊休眠,等到⽣产者往缓冲区添加数据之后,再唤醒消费者。
通常采⽤进程间通信的⽅法解决该问题。
如果解决⽅法不够完善,则容易出现死锁的情况。
出现死锁时,两个线程都会陷⼊休眠,等待对⽅唤醒⾃⼰。
该问题也能被推⼴到多个⽣产者和消费者的情形。
2、问题分析该问题需要注意的⼏点:1. 在缓冲区为空时,消费者不能再进⾏消费2. 在缓冲区为满时,⽣产者不能再进⾏⽣产3. 在⼀个线程进⾏⽣产或消费时,其余线程不能再进⾏⽣产或消费等操作,即保持线程间的同步4. 注意条件变量与互斥锁的顺序由于前两点原因,因此需要保持线程间的同步,即⼀个线程消费(或⽣产)完,其他线程才能进⾏竞争CPU,获得消费(或⽣产)的机会。
对于这⼀点,可以使⽤条件变量进⾏线程间的同步:⽣产者线程在product之前,需要wait直⾄获取⾃⼰所需的信号量之后,才会进⾏product的操作;同样,对于消费者线程,在consume之前需要wait直到没有线程在访问共享区(缓冲区),再进⾏consume的操作,之后再解锁并唤醒其他可⽤阻塞线程。
操作系统实验——PV操作实现生产者消费者模型

/** * 单个生产者类 * @author Vfdxvffd * @count 生产的物品数量标号 */ class Producer implements Runnable{ int count = 0; //数量 @Override public void run() { while(count < 20) { //最多生产20件商品
Global.empty.Wait(); /*要生产物品了,给剩余空 闲缓冲区数量--,如果减完后变为负数,则说明当前没 有空闲缓冲区,则加入等待队列*/ //临界区,生产商品 int index = count % 2; Global.buffer[index] = count; System.out.println("生产者在缓冲区"+index+"中生产了物品"+count); count++;
假如生产者号生产了0号商品,但此时他还没做Global.pCount++这一步操作,CPU将执行权切换到生产者2号,这时Global.pCount的值还是 刚刚的0,没有加1,所以又会生产出一个0号商品,那消费者也同理,消费完还没加1,就被切换了执行权。
那就有个问题,如果我们将Global.pCount++这一步提前能不能解决问题呢,当然也是不行的,因为可能++完还没输出就被切换执行权,那下次 执行权回来时候就会继续执行输出操作,但此时的Global.pCount的值已经不知道加了多少了。
/*remove a process P from the waiting queue*/ wakeup(P); } }
信号量的应用
利用JAVA多线程并发机制解决生产者—消费者问题

A b t a t T e p p r a aye d d srb s te c mpiae rc s fmut t e d d J s r c : h a e n lz s a ecie h o l td p o es o li hra e AVA y c rnz t n me h ns a d n c — sn h o iai c a im n o
21 车2月 O0
电 脑 学 习
第1 期
利 用 J V 多线程 并发机制解 决生产者一 消费者 问题 A A
陈 益
摘 要 : 本文分析并描述 了J V A A多线程并发过程 中的同步机制及消息通信机制的基本原理 . 探讨如何运用多线程同步机制
和 消 息 互 通 机 制切 实 解 决 生 产 者 和 消费 者 之 间 的问 题 。
T ra h d类提供 了各种 与线 程有关 的方法 ,方 便 .本 文 将 采 用 继 承 T ra 来 实 现 多 h d类 e
线程技术 。但是在程序中 , 所有线程共 享同一 内存空 间, 两 个或多个线程可能 同时访 问同一变量或运行 同一对 象的同
Jv aa语言和 Jv 虚拟机提供 了完全 意义上的多线程支 aa 持 ,其 内置语言 级的多线程机制让用户更 方便地实现多个 并行程序 的开发 ,从 语言级上提供各个线 程问协调工作 的 调度能力 , 降低并发程序设计的难度 。在 Jv aa中, 多线程的
建 立 有 两 种 方 法 : 继 承 T ra hed类 和 实 现 R na l 口 。 un be接
te b sc p icpe fme sg o h a i rn ilso sa e c mmu c to c a im, x lr h o ue mut tra y c rnzto l h - i n ain me h s e po ̄ n wo t s li he d s ho ain l - n i  ̄c a im ns a d me sg x h n e me h ns ta ud e e t ey sle te p be ewe n po u esa o s mes n sa e e c a g c a im h twol f ci l ov h r lms b t e rd c r nd c n u r. v o litra e Ke wo d Mut-he d d y r: S n ho iain y c r nzt o C nt o cm ̄n e c P o u e rd c r C nu r o s me
操作系统课程设计“生产者-消费者”问题

《操作系统》课程设计题目:“生产者-消费者”问题学院:信息工程学院专业:计算机科学与技术班级:计科1302*名:***指导老师:***2016年1月 15日目录一、课程设计目标 (2)二、课题内容 (2)1.实验目的 (2)2、实验环境 (2)3、实验要求 (2)三、设计思路 (3)1.信号量的设置 (3)2.系统结构 (4)3.程序流程图 (5)4.P V操作代码 (6)四、源代码 (7)五、运行与测试 (10)六、心得体会 (12)一、课程设计目标学习System V的进程间通信机制,使用信号量和共享内存实现经典进程同步问题“生产者-消费者”问题。
具体要求:1.创建信号量集,实现同步互斥信号量。
2.创建共享内存,模拟存放产品的公共缓冲池。
3.创建并发进程,实现进程对共享缓冲池的并发操作。
二、课题内容1.实验目的(1)掌握基本的同步互斥算法,理解生产者和消费者同步的问题模型。
(2)了解linux中多线程的并发执行机制,线程间的同步和互斥。
2、实验环境:C/C++语言编译器3、实验要求(1)创建生产者和消费者线程在linux环境下,创建一个控制台进程,在此进程中创建n个线程来模拟生产者或者消费者。
这些线程的信息由本程序定义的“测试用例文件”中予以指定。
(2)生产和消费的规则在按照上述要求创建线程进行相应的读写操作时,还需要符合以下要求:①共享缓冲区存在空闲空间时,生产者即可使用共享缓冲区。
②从上边的测试数据文件例子可以看出,某一生产者生产一个产品后,可能不止一个消费者,或者一个消费者多次地请求消费该产品。
此时,只有当所有的消费需求都被满足以后,该产品所在的共享缓冲区才可以被释放,并作为空闲空间允许新的生产者使用。
③每个消费者线程的各个消费需求之间存在先后顺序。
例上述测试用例文件包含一行信息“5 C 3 l 2 4”,可知这代表一个消费者线程,该线程请求消费1,2,4号生产者线程生产的产品。
而这种消费是有严格顺序的,消费1号线程产品的请求得到满足后才能继续往下请求2号生产者线程的产品。
生产者和消费者问题

关于linux中多进程(线程)同步和互斥Linux设备驱动中必须解决的一个问题是多个进程对共享资源的并发访问,并发访问会导致竞态,linux提供了多种解决竞态问题的方式,这些方式适合不同的应用场景。
Linux内核是多进程、多线程的操作系统,它提供了相当完整的内核同步方法。
内核同步方法列表如下:中断屏蔽原子操作自旋锁读写自旋锁顺序锁信号量读写信号量BKL(大内核锁)Seq锁一、并发与竞态:定义:并发(concurrency)指的是多个执行单元同时、并行被执行,而并发的执行单元对共享资源(硬件资源和软件上的全局变量、静态变量等)的访问则很容易导致竞态(race conditions)。
在linux中,主要的竞态发生在如下几种情况:1、对称多处理器(SMP)多个CPU特点是多个CPU使用共同的系统总线,因此可访问共同的外设和存储器。
2、单CPU内进程与抢占它的进程3、中断(硬中断、软中断、Tasklet、底半部)与进程之间只要并发的多个执行单元存在对共享资源的访问,竞态就有可能发生。
如果中断处理程序访问进程正在访问的资源,则竞态也会会发生。
多个中断之间本身也可能引起并发而导致竞态(中断被更高优先级的中断打断)。
解决竞态问题的途径是保证对共享资源的互斥访问,所谓互斥访问就是指一个执行单元在访问共享资源的时候,其他的执行单元都被禁止访问。
访问共享资源的代码区域被称为临界区,临界区需要以某种互斥机制加以保护,中断屏蔽,原子操作,自旋锁,和信号量都是linux设备驱动中可采用的互斥途径。
临界区和竞争条件:所谓临界区(critical regions)就是访问和操作共享数据的代码段,为了避免在临界区中并发访问,编程者必须保证这些代码原子地执行——也就是说,代码在执行结束前不可被打断,就如同整个临界区是一个不可分割的指令一样,如果两个执行线程有可能处于同一个临界区中,那么就是程序包含一个bug,如果这种情况发生了,我们就称之为竞争条件(race conditions),避免并发和防止竞争条件被称为同步。
操作系统 课程设计

课程设计报告课程名称操作系统课题名称利用多线程模拟实生产者/消费者问题.专业通信工程班级学号姓名指导教师田娟秀、谭小兰20 年月日湖南工程学院课程设计任务书课程名称操作系统课题利用多线程模拟实现生产者/消费者问题.专业班级通信工程学生姓名学号指导老师田娟秀、谭小兰审批任务书下达日期20 年6 月日任务完成日期20 年6 月日一、设计内容与设计要求1.设计内容:课题4:利用多线程模拟实现生产者/消费者问题。
生产者/消费者问题是一个多线程同步问题的经典案例。
该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。
生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。
与此同时,消费者也在缓冲区消耗这些数据。
该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
要解决该问题,就必须让生产者在缓冲区满时休眠,等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。
同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。
通常采用进程间通信的方法解决该问题,如采用信号量方法。
如果解决方法不够完善,则容易出现死锁的情况。
出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。
2 选题方案:所选题目根据学号确定,学号模7加1,即(学号%7+1)。
如你的学号为9,则所选题目号为:9%7+1=(题目3)。
3设计要求:3.1 课程设计报告规范(1)需求分析a.程序的功能。
b.输入输出的要求。
(2)概要设计a.程序由哪些模块组成以及模块之间的层次结构、各模块的调用关系;每个模块的功能。
b.课题涉及的数据结构和数据库结构;即要存储什么数据,这些数据是什么样的结构,它们之间有什么关系等。
(3)详细设计a.采用C语言定义相关的数据类型。
b.写出各模块的类C码算法。
c.画出各函数的调用关系图、主要函数的流程图。
操作系统实验报告三大问题之生产者与消费者问题

计算机操作系统实验报告题目三大经典问题之生产者与消费者问题一、课程设计的性质与任务1、加深对并发协作进程同步与互斥概念的理解。
通过编写程序实现进程同步和互斥,使学生掌握有关进程(线程)同步与互斥的原理,以及解决进程(线程)同步和互斥的算法,从而进一步巩固进程(线程)同步和互斥等有关的内容。
2、掌握进程和线程的概念,进程(线程)的控制原语或系统调用的使用。
3、了解Windows2000/XP中多线程的并发执行机制,线程间的同步和互斥。
学习使用Windows2000/XP中基本的同步对象,掌握相应的API函数。
4、培养学生能够独立进行知识综合,独立开发较大程序的能力。
5、培养提高学生软件开发能力和软件的调试技术。
6、培养学生开发大型程序的方法和相互合作的精神。
7、培养学生的创新意识。
8、培养学生的算法设计和算法分析能力。
9、培养学生对问题进行文字论述和文字表达的能力。
二、课程设计的内容及其要求在Windows?XP、Windows?2000等操作系统下,使用的VC、VB、Java或C等编程语言,采用进程(线程)同步和互斥的技术编写程序实现生产者消费者问题或哲学家进餐问题或读者-写者问题或自己设计一个简单进程(线程)同步和互斥的实际问题。
要求:(1)经调试后程序能够正常运行。
(2)采用多进程或多线程方式运行,体现了进程(线程)同步互斥的关系。
(3)程序界面美观。
三、实验原理本实验要求利用PV操作实现解决生产者——消费者问题中的同步问题。
此问题描述的是一群生产者进程在生产产品并将这些产品提供给消费者进程去消费,在两者之间设置了一个具有n个缓冲区的缓冲池,生产者进程将它所生产的产品放入一个缓冲区,消费者进程可从缓冲区中取走产品去消费,但它们之间必须保持同步,即不允许消费者进程到一个空缓冲区去取产品,也不允许生产者进程向一个已装满且尚未取出的缓冲区中投放产品,并且生产者消费者互斥使用缓冲区。
四、实验原理图五、算法实现(1)有一个生产者线程ProduceThread,有1个消费者进程CustomerThread;缓冲区为shareList。
生产者消费者问题 操作系统课程设计

生产者消费者问题操作系统课程设计生产者消费者问题是操作系统中常见的一个并发问题,本课程设计旨在帮助学生深入理解该问题及其解决方案。
课程设计内容包括:
1. 生产者消费者问题的定义、特点和解决方案
2. 生产者消费者问题的算法设计与实现
3. 多线程并发编程实践
4. 操作系统调度与同步机制实践
5. 生产者消费者问题的应用场景与案例分析
通过本课程设计,学生将能够掌握操作系统中的重要问题与解决方案,并具备多线程并发编程的实践技能,为以后的操作系统开发与应用打下坚实的基础。
- 1 -。
消费者生产者问题

北方民族大学课程设计报告系(部、中心)计算机科学与工程学院姓名杨和平学号 20060309 专业计算机科学与工程学院班级 1 同组人员课程名称计算机操作系统课程设计设计题目多进程同步方法解决生产者-消费者问题起止时间 2008年12月15日—2008年12月26日成绩指导教师签名韩强北方民族大学教务处制多进程同步方法解决生产者-消费者问题摘要本文论述了多进程同步方法解决生产者-消费者问题的过程。
该程序使学生对操作系统的工作机制有了初步的了解,其主要目的是使学生了解和撑握在Linux系统平台下的C语言编程,用来解决实现生活中遇到的问题。
并以Linux 系统开发平台,以及虚拟机来实现。
关键字:生产者-消费者问题,Linux系统平台,虚拟机,信号量,线程(thread)目录一、课程设计所需设备 (4)二、课程设计预期目的 (4)三、课程设计任务 (4)四、课程设计基本思想 (4)五.详细设计 (5)5.1.调试工具简介VI(VISUAL EDITOR) (5)5.2、调试问题分析 (5)5.3、程序流程图 (7)5.4、程序自定义函数 (8)5.5、系统函数调用 (8)六.源程序清单 (10)6.1、/*源程序PV.C*/ (10)6.2、编译及运行结果 (15)七.课程设计总结 (19)符录:参考文献 (19)多进程同步方法解决生产者-消费者问题一、课程设计所需设备计算机一台,Red Hat linux9.03系统一套。
二、课程设计预期目的通过研究Linux 的进程机制和信号量实现生产者消费者问题的并发控制。
三、课程设计任务1、每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容,当前指针位置和生产者/消费者县城的标识符;2、生产者和消费者各有两个以上;3、多个生产者或多个消费者之间须有共享对缓冲区进行操作的函数码。
4、有界缓冲区内设有20个存储单元,放入/取出的数据项设定为1-20这20个整型数。
操作系统实验报告-进程同步与互斥

操作系统实验报告-进程同步与互斥(总12页)--本页仅作为文档封面,使用时请直接删除即可----内页可以根据需求调整合适字体及大小--《进程同步与互斥》实验报告学号姓名专业、班实验地点指导教师时间一、实验目的1、掌握基本的进程同步与互斥算法,理解生产者-消费者问题。
2、学习使用Windows 2000/XP中基本的同步对象,掌握相关API的使用方法。
3、了解Windows 2000/XP中多线程的并发执行机制,实现进程的同步与互斥。
4、设计程序,实现生产者-消费者进程(线程)的同步与互斥;二、实验环境Windows 2000/XP + Visual C++三、实验内容以生产者-消费者模型为依据,在Windows 2000/XP环境下创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。
四、设计思路和流程框图生产者进程的功能:生产东西,供消费者消费;消费者进程的功能:消费生产者生产的东西。
生产者生产产品并存入缓冲区供消费者取走使用,消费者从缓冲器内取出产品去消费。
在生产者和消费者同时工作时,必须禁止生产者将产品放入已装满的缓冲器内,禁止消费者从空缓冲器内取产品。
五、源程序(含注释)清单六、测试结果以及实验总结1、通过实验进一步了解了基本的进程同步与互斥算法,理解生产者-消费者问题2、掌握了相关API的使用方法。
3、了解到进程是一个可以拥有资源的基本单位,是一个可以独立调度和分派的基本单位。
而线程是进程中的一个实体,是被系统独立调度和分配的基本单位,故又称为轻权(轻型)进程(Light Weight Process)。
4、了解到同步对象是指Windows中用于实现同步与互斥的实体,包括信号量(Semaphore)、互斥量(Mutex)、临界区(Critical Section)和事件(Events)等。
本实验中使用到信号量、互斥量和临界区三个同步对象。
成绩备注:实验报告文档的名称:姓名_实验编号(例如:张三_1、张三_2);实验报告发送到。
生产者和消费者问题实验报告

格式: V。IDEnterCriticalSection( LPCRITICAL_SECTI。NIpCnticalSection ); LeaveCriticalSection的用法 功能:释放指定临界区对象的所有权。 格式: V。IDLeaveCriticalSection( LPCRITICAL.SECTI。NIpCriticalSection ); 2)程序结构 MI-I和序结构图 3)数据结构 (1)用一个整型数组Buffer-Critical来代表缓冲区。不管是生产产品还是对已有产品的消费都
Fer(inti-∙zi<R.reqvestHunU∙∙)
n_tħrei。.re<∣ι>tst[1]-((Thread!i⅞Fφ∙)(p))->thre⅛d.reqvest(1];
$10,P(LSl刊);
F∙r(l-∙U<R..req<∣p⅝tHuAU*∙)<
printfCXoo⅞uι⅞erVdrequesttoconς∣>aeVdpro^uct∖n-t∙-serlil.n_thr^a<l_requ«Mlt_for_sefuiphorPVanFarSinglp。bject(b_S^Mphor»(ii_thrp^d_reqiiest[i])v*-1);
文件G)⅛M∙Z)2«(X)收就")工具(D隅船。i) r^i∙-。CAftφct∙taisg4S∙S∖n<s∖Mmm6lr∙t0tA4面3f⅞文件夹∖*JfFl 文件和文件关任务 J创建一个新文件夹 θ将这个文件英宣布到 WHtb H共享,及伴英 IT*+6Y。rkSP∙c∙ Urn C*÷Ssιrc∙6KB Un VV忖Inttllistns 25KB 10簪巷
生产者消费者问题实现

生产者消费者问题实现班级姓名学号一.实验目的1.熟悉临界资源、信号量及PV操作的定义与物理意义2.了解线程通信的方法3.掌握线程互斥与同步的相关知识4.掌握用信号量机制解决线程之间的同步与互斥问题5.实现生产者-消费者问题,深刻理解线程同步问题二、实验的硬件、软件平台硬件:计算机软件:操作系统win10应用软件:Dev C++三、实验原理生产者-消费者问题是一个经典的线程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。
在同一个线程地址空间内执行的两个线程。
生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。
消费者线程从缓冲区中获得物品,然后释放缓冲区。
当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。
当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
多个生产/消费者在有界缓冲上操作。
它利用N个字节的共享内存作为有界循环缓冲区,利用写一字符模拟放一个产品,利用读一字符模拟消费一个产品。
当缓冲区空时消费者应阻塞睡眠,而当缓冲区满时生产者应当阻塞睡眠。
一旦缓冲区中有空单元,生产者线程就向空单元中入写字符,并报告写的内容和位置。
一旦缓冲区中有未读过的字符,消费者线程就从该单元中读出字符,并报告读取位置。
生产者不能向同一单元中连续写两次以上相同的字符,消费者也不能从同一单元中连续读两次以上相同的字符。
在进行多线程编程时,由于资源共享和进程间合作而造成进程间相互制约,难免还要碰到两个问题,那就线程间的互斥与同步:线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。
当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。
实验一生产者消费者问题

实验一生产者消费者问题一、实验目的1.掌握进程(线程)的同步与互斥。
2.掌握生产者消费者问题的实现方法。
3.掌握多线程编程方法。
二、相关函数VC提供一系列函数用于实现多线程编程以及线程的互斥与同步。
(1)创建线程HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄,其中各参数说明如下:✧lpThreadAttributes:指向一个SECURITY_ATTRIBUTES 结构的指针,该结构决定了线程的安全属性,一般置为NULL;✧dwStackSize:指定了线程的堆栈深度,一般都设置为0;✧lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。
main()函数是主线程的入口函数,同样,新创建的线程也需要一个入口函数,lpStartAddress 就是指示该函数的地址。
并且这个函数的定义应遵循下面的声明形式DWORD WINAPI ThreadProc(LPVOID lpParameter);✧lpParameter:指定了线程执行时传送给线程的32位参数,即线程函数的参数;✧dwCreationFlags:控制线程创建的附加标志,可以取两种值。
如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于阻塞状态,并不马上执行,直至函数ResumeThread被调用;✧lpThreadId:该参数返回所创建线程的ID;✧函数返回值:如果创建成功则返回线程的句柄,否则返回NULL。
线程同步互斥经典问题

线程同步互斥经典问题一、什么是线程同步互斥经典问题呢?1. 咱得先知道,线程就像是一群小工人,在计算机这个大工厂里干活。
线程同步互斥经典问题啊,就好比这些小工人在干活的时候会遇到的一些麻烦事儿。
比如说,有个资源就像一个工具,好多小工人都想用,那咋整呢?这就是线程同步互斥要解决的问题。
2. 再具体点说,经典问题里有生产者 - 消费者问题。
想象一个面包店,生产者就是做面包的师傅,消费者就是来买面包的顾客。
做面包得用烤箱这个资源,不能好几个师傅同时往一个烤箱里塞面包坯子吧,这就需要同步,让师傅们一个一个来用烤箱。
而顾客呢,要是面包还没做好就来拿,那也不行,这就是互斥,顾客得等着面包做好了才能拿。
3. 还有读者 - 写者问题。
把一个文件当成是一个宝贝,读者就是来看这个宝贝的人,写者就是来修改这个宝贝的人。
好多人可以同时看这个宝贝,但是如果有人在修改这个宝贝,那就不能同时又有人看又有人改了,这时候就得有个规则来协调,啥时候读者能看,啥时候写者能改,这就是线程同步互斥在这个问题里的体现。
4. 哲学家就餐问题也很有趣。
把哲学家想象成线程,筷子想象成资源。
每个哲学家都需要两根筷子才能吃饭,但是筷子就那么多,如果大家都乱抢,那就会出乱子。
这就需要一些策略来保证哲学家们能有条不紊地拿到筷子吃饭,这也是线程同步互斥要处理的情况。
二、为啥这些问题很重要呢?1. 在计算机的世界里,如果这些线程同步互斥问题处理不好,就像一个乱成一团的工厂。
程序可能会出错,数据可能会被破坏。
比如说,要是多个线程同时修改一个数据,那这个数据最后可能就变得乱七八糟的,就像好多人同时在一张纸上乱写乱画,最后谁也不知道纸上原本该是什么内容了。
2. 从性能的角度看,如果没有好的同步互斥机制,可能会导致一些线程一直在等待,资源得不到有效利用。
就好比工人一直在等工具,但是工具却被闲置在一边,这多浪费啊。
三、那怎么解决这些线程同步互斥经典问题呢?1. 可以用信号量。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
学号:课程设计题目用多线程同步方法解决生产者-消费者问题(Producer-Consumer Problem)学院计算机科学与技术学院专业软件工程班级姓名指导教师年月日目录目录 (1)课程设计任务书 (1)正文 (2)1.设计目的与要求 (2)1.1设计目的 (2)1.2设计要求 (2)2.设计思想及系统平台 (2)2.1设计思想 (2)2.2系统平台及使用语言 (2)3.详细算法描述 (3)4.源程序清单 (5)5.运行结果与运行情况 (10)6.调试过程 (13)7.总结 (13)本科生课程设计成绩评定表 ..................................................... 错误!未定义书签。
课程设计任务书学生姓名:专业班级:指导教师:工作单位:计算机科学与技术学院题目: 用多线程同步方法解决生产者-消费者问题(Producer-Consumer Problem)初始条件:1.操作系统:Linux2.程序设计语言:C语言3.有界缓冲区内设有20个存储单元,其初值为0。
放入/取出的数据项按增序设定为1-20这20个整型数。
要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)1.技术要求:1)为每个生产者/消费者产生一个线程,设计正确的同步算法2)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的当前全部内容、当前指针位置和生产者/消费者线程的自定义标识符。
3)生产者和消费者各有两个以上。
4)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。
2.设计说明书内容要求:1)设计题目与要求2)总的设计思想及系统平台、语言、工具等。
3)数据结构与模块说明(功能与流程图)4)给出用户名、源程序名、目标程序名和源程序及其运行结果。
(要注明存储各个程序及其运行结果的主机IP地址和目录。
)5)运行结果与运行情况(提示: (1)有界缓冲区可用数组实现。
(2)编译命令可用:cc -lpthread -o 目标文件名源文件名(3)多线程编程方法参见附件。
)3. 调试报告:1)调试记录2)自我评析和总结上机时间安排:18周一~ 五 08:0 - 12:00指导教师签名:年月日系主任(或责任教师)签名:年月日正文1.设计目的与要求1.1设计目的通过研究Linux的线程机制和信号量实现生产者消费者问题(Producer-Consumer Problem)的并发控制。
1.2设计要求1)为每个生产者/消费者产生一个线程,设计正确的同步算法2)每个生产者/消费者对该存储区进行操作后,即时显示该存储区的全部内容、当前指针位置和生产者/消费者线程的自定义标识符。
3)生产者和消费者各有两个以上。
4)多个生产者/消费者之间须共享对存储区进行操作的函数代码。
2.设计思想及系统平台2.1设计思想在本问题中,共需要一个Mutex和两个Semaphore.其中,Mutex是用来锁定临界区的,以解决对共享数据buffer的互斥访问问题(无论是对生成者还是对消费者);我们共需要两个Semaphore,这是因为在本问题中共有两个稀缺资源.第一种是"非空"这种资源,是在消费者之间进行竞争的.第二种是"非满"这种资源,是在生产者之间进行竞争的.所以,一般来说,需要锁定临界区,就需要Mutex;有几种稀缺资源就需要几个Semaphore.对稀缺资源的分析不能想当然.稀缺资源不一定是指被共享的资源,很多时候是指线程会被阻塞的条件(除了要进临界区被阻塞外).在生产者消费者问题中,消费者会在缓冲区为空时被阻塞,所以"非空"是一种稀缺资源;需要设置一个信号量consumer_semaphore,初值设为0;生产者会在缓冲区为满时被阻塞,所以"非满"也是一种稀缺资源.需要设置一个信号量producer_semaphore,初值设为buffer的大小MAX_BUFFER2.2系统平台及使用语言本课程设计在Linux操作系统下,使用C语言完成。
用到的工具主要有GCC编译器和VI编辑器。
3.详细算法描述共享数据:Semaphore buffer_mutex=1;Semaphore producer_semaphore=MAX_BUFFER;Semaphore consumer_semaphore=0;int buffer[MAX_BUFFER];Producer线程的处理函数:while(1){Wait(producer_semaphore);Wait(buffer_mutex);Buffer[pn]=product;pn=(pn+1)%MAX_BUFFER;Signal(consumer_semaphore);Signal(buffer_mutex);Sleep();}producer线程的处理函数流程图如下:consumer线程的处理函数:while(1){Wait(consumer_semaphore);Wait(buffer_mutex);Consume=buffer[cn];cn=(cn+1)%MAX_BUFFER;Signal(producer_semaphore);Signal(buffer_mutex);Sleep();}consumer线程的处理函数流程图如下:4.源程序清单用户名:rj070126(IP:192.168.2.254)源程序名:/home/rj070126/pc.c目标程序名:/home/rj070126/pc运行结果:/home/rj070126/output.txt源程序清单如下:#include<stdio.h>#include<stdlib.h>#include<string.h>#include<pthread.h>#include<semaphore.h>#include<sys/types.h>#include<errno.h>#include<unistd.h>#include<signal.h>#include<time.h>#define NUM_THREADS_P 5 /*define the number of producer*/ #define NUM_THREADS_C 5 /*define the number of consumer*/ #define MAX_BUFFER 20 /*define the number of buffer*/#define RUN_TIME 20 /*define the run time*/int buffer[MAX_BUFFER]; /*difine the buffer */int produce_pointer=0,consume_pointer=0;sem_t producer_semaphore,consumer_semaphore,buffer_mutex; pthread_t threads_p[NUM_THREADS_P]; /*producer*/pthread_t threads_c[NUM_THREADS_C]; /*consumer*/FILE* fd;void *producer_thread(void *tid);void *consumer_thread(void *tid);void showbuf();void handler(){int i;for(i=0;i<NUM_THREADS_P;i++)pthread_cancel(threads_p[i]);for(i=0;i<NUM_THREADS_C;i++)pthread_cancel(threads_c[i]);}int main(){int i;signal(SIGALRM,handler);fd=fopen("output.txt","w"); /*open a file to save the result*/sem_init(&producer_semaphore,0,MAX_BUFFER); /*set the value of semaphores*/ sem_init(&consumer_semaphore,0,0);sem_init(&buffer_mutex,0,1);for(i=0;i<MAX_BUFFER;i++)buffer[i]=0; /*initiate the buffer*//*create the threads*/for(i=0;i<NUM_THREADS_P;i++)pthread_create(&threads_p[i],NULL,(void*)producer_thread,(void*)(i+1));for(i=0;i<NUM_THREADS_C;i++)pthread_create(&threads_c[i],NULL,(void*)consumer_thread,(void *)(i+1));alarm(RUN_TIME); /*set time to run*//*wait the threads to exit*/for(i=0;i<NUM_THREADS_P;i++)pthread_join(threads_p[i],NULL);for(i=0;i<NUM_THREADS_C;i++)pthread_join(threads_c[i],NULL);/*destroy the semaphores*/sem_destroy(&producer_semaphore);sem_destroy(&consumer_semaphore);sem_destroy(&buffer_mutex);fclose(fd);return 0;}void *producer_thread(void *tid){/*the thread can be canceled by other thread*/pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);while(1){sem_wait(&producer_semaphore);srand((int)time(NULL)*(int)tid);sleep(rand()%2+1); /*one or two seconds to produce*/while((produce_pointer+1)%20==consume_pointer);sem_wait(&buffer_mutex);buffer[produce_pointer]=rand()%20+1;produce_pointer=(produce_pointer+1)%20;if(produce_pointer==0){ /*if buffer was filled to the 19th*/printf("producer:%d pointer_p:%2d produced:%2d\n",(int)tid,19,buffer[19]);fprintf(fd,"producer:%d pointer_p:%2d produced:%2d\n",(int)tid,19,buffer[19]);}else{printf("producer:%d pointer_p:%2d produced:%2d\n",(int)tid,produce_pointer-1,buffer[produce_pointer-1]);fprintf(fd,"producer:%d pointer_p:%2d produced:%2d\n",(int)tid,produce_pointer-1,buffer[produce_pointer-1]);}showbuf();sem_post(&buffer_mutex);sem_post(&consumer_semaphore); /*inform the consumer the buffer is not empty*/srand((int)time(NULL)*(int)tid);sleep(rand()%5+1); /*wait a few seconds ,then continue producing*/ }return ((void*)0);}void *consumer_thread(void *tid){/*the thread can be canceled by other thread*/pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);while(1){sem_wait(&consumer_semaphore);srand((int)time(NULL)*(int)tid);sleep(rand()%2+1); /*one or two seconds to consume*/sem_wait(&buffer_mutex);printf("consumer:%d pointer_c:%2d consumed:%2d\n",(int)tid,consume_pointer,buffer[consume_pointer]);fprintf(fd,"consumer:%d pointer_c:%2d consumed:%2d\n",(int)tid,consume_pointer,buffer[consume_pointer]);buffer[consume_pointer]=0;consume_pointer=(consume_pointer+1)%20;showbuf();sem_post(&buffer_mutex);sem_post(&producer_semaphore);srand((int)time(NULL)*(int)tid);sleep(rand()%5+1); /*wait a few seconds ,then continue consuming*/ }return ((void*)0);}/*show the content of buffer*/void showbuf(){int i;printf("buffer:");fprintf(fd,"buffer:");for(i=0;i<MAX_BUFFER;i++){printf("%2d ",buffer[i]);fprintf(fd,"%2d ",buffer[i]);}printf("\n\n");fprintf(fd,"\n\n");}5.运行结果与运行情况程序运行结果如下:producer:1 pointer_p: 0 produced:20buffer:20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:3 pointer_p: 1 produced:13buffer:20 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:2 pointer_p: 2 produced: 6buffer:20 13 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:4 pointer_p: 3 produced:14buffer:20 13 6 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:5 pointer_p: 4 produced:20buffer:20 13 6 14 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:2 pointer_c: 0 consumed:20buffer: 0 13 6 14 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:1 pointer_p: 5 produced:20buffer: 0 13 6 14 20 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:1 pointer_c: 1 consumed:13buffer: 0 0 6 14 20 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:3 pointer_c: 2 consumed: 6buffer: 0 0 0 14 20 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:4 pointer_c: 3 consumed:14buffer: 0 0 0 0 20 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:5 pointer_c: 4 consumed:20buffer: 0 0 0 0 0 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:3 pointer_p: 6 produced: 1buffer: 0 0 0 0 0 20 1 0 0 0 0 0 0 0 0 0 0 0 0 0 producer:2 pointer_p: 7 produced:14buffer: 0 0 0 0 0 20 1 14 0 0 0 0 0 0 0 0 0 0 0 0 consumer:3 pointer_c: 5 consumed:20buffer: 0 0 0 0 0 0 1 14 0 0 0 0 0 0 0 0 0 0 0 0 producer:4 pointer_p: 8 produced: 6buffer: 0 0 0 0 0 0 1 14 6 0 0 0 0 0 0 0 0 0 0 0 consumer:5 pointer_c: 6 consumed: 1buffer: 0 0 0 0 0 0 0 14 6 0 0 0 0 0 0 0 0 0 0 0 producer:5 pointer_p: 9 produced: 8buffer: 0 0 0 0 0 0 0 14 6 8 0 0 0 0 0 0 0 0 0 0 consumer:2 pointer_c: 7 consumed:14buffer: 0 0 0 0 0 0 0 0 6 8 0 0 0 0 0 0 0 0 0 0 consumer:5 pointer_c: 8 consumed: 6buffer: 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0 producer:1 pointer_p:10 produced:18buffer: 0 0 0 0 0 0 0 0 0 8 18 0 0 0 0 0 0 0 0 0buffer: 0 0 0 0 0 0 0 0 0 0 18 0 0 0 0 0 0 0 0 0 producer:2 pointer_p:11 produced:10buffer: 0 0 0 0 0 0 0 0 0 0 18 10 0 0 0 0 0 0 0 0 producer:4 pointer_p:12 produced:10buffer: 0 0 0 0 0 0 0 0 0 0 18 10 10 0 0 0 0 0 0 0 consumer:4 pointer_c:10 consumed:18buffer: 0 0 0 0 0 0 0 0 0 0 0 10 10 0 0 0 0 0 0 0 producer:3 pointer_p:13 produced: 3buffer: 0 0 0 0 0 0 0 0 0 0 0 10 10 3 0 0 0 0 0 0 consumer:3 pointer_c:11 consumed:10buffer: 0 0 0 0 0 0 0 0 0 0 0 0 10 3 0 0 0 0 0 0 consumer:2 pointer_c:12 consumed:10buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 producer:1 pointer_p:14 produced: 6buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 3 6 0 0 0 0 0 consumer:1 pointer_c:13 consumed: 3buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0 producer:2 pointer_p:15 produced:18buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 18 0 0 0 0 consumer:5 pointer_c:14 consumed: 6buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 18 0 0 0 0 producer:1 pointer_p:16 produced: 6buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 18 6 0 0 0 producer:3 pointer_p:17 produced:19buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 18 6 19 0 0 consumer:1 pointer_c:15 consumed:18buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 19 0 0 producer:5 pointer_p:18 produced: 7buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 19 7 0 consumer:3 pointer_c:16 consumed: 6buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 7 0 producer:4 pointer_p:19 produced:14buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 7 14 consumer:5 pointer_c:17 consumed:19buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 14 consumer:4 pointer_c:18 consumed: 7buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 producer:1 pointer_p: 0 produced: 4buffer: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 consumer:2 pointer_c:19 consumed:14buffer: 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 consumer:1 pointer_c: 0 consumed: 4buffer: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0buffer: 0 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0producer:3 pointer_p: 2 produced:13buffer: 0 15 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0producer:2 pointer_p: 3 produced: 3buffer: 0 15 13 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0说明:“producer:2”是指自定义标号为2的producer,“pointer_p:3”是指该producer的指针,“produced:3”是指该producer在buffer[3]里写入3,“buffer: 0 15 13 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ”是指该producer进行写操作后存储区的内容。