用多线程同步方法解决生产者-消费者问题

合集下载

生产者/消费者经典同步问题的深入探究

生产者/消费者经典同步问题的深入探究



aa 要 简要 描 述 Jv 语 言 多线 程机 制 ,阐述 了操 作 系统 中生产 者/ 消 费者这 个经 典 同步 问题 ,探 讨 了该 问题 的 多种 高效 解 决策略 ,并 通过 Jv 言的 多线程 编程技 术 , aa语 给 出 了实现 此 问题 相应 解决 策略 的代码 。 旨在 为研 究 pou e —cnu e p t rs rd c r o sm r a en t
费者 问题 ,以助人们更好地透解同步概念及其实现方法 。


Jv a a多线 程 机 制
多 线 程 是 允 许 在 程序 中并 发 执 行 多 个 间: 为各生产 者每 次装入数 3 作
据 都 需 要 消 耗 空 缓 冲 区 , 且 提 供 满 缓 冲 区 ; 各 消 费 者 每 次取 并 而 出 数 据 都 需 要 消 耗 满 缓 冲 区 , 且 提 供 空 缓 冲 区 。 因此 , 并 生产 者 和 消 费 者 之 间 存 在 同步 关 系 。 为 了提 高 系 统 的 效 率 , 要求 生 产 者 与 消 费 者 可 以 同 时 对 缓 冲池 进 行 操 作 , 就 是 说 有 生 产 者 正 也
有 一 群 生 产 者 ( 1 2 P ) ( ) 向具 有 k个 缓 冲 区 的 P 、P … n 进 线 程
模式在这些技术的发 展中起着重要作用。在现 代操作系统 中,
利 用进 f ) 间 的并 发性 实 现 程 序 中并 发 成分 的并 行 执 行 ,可 线 程
缓冲池中装入数据 ,一群 消费者 ( 1 2 m) ( ) C 、C …C 进 线 程从该 缓冲池中取出数据 ,进行处理。其 中 P 和 q 都是并发进 ( ) i 线 程,只要缓冲池未满 ,P 就可把产生的数据放入缓冲区;类似 i

操作系统生产者消费者问题实验报告

操作系统生产者消费者问题实验报告

实验报告二实验名称:一、生产者-消费者问题的多线程解决方案二、设计一个执行矩阵乘法的多线程程序日期:2015-10-22 班级:13级计科学号:姓名:一、实验目的1.掌握线程的同步与互斥2.掌握生产者消费者的实现问题3.掌握多线程的编程方法4.掌握矩阵乘法的基本计算原理以及实现二、实验内容1.生产者-消费者问题的多线程解决方案2.设计一个执行矩阵乘法的多线程程序三、项目要求与分析1.请查阅资料,掌握线程创建的相关知识以及矩阵乘法的相关知识,了解java语言程序编写的相关知识2.理解线程的实验步骤在本次试验中,以“生产者-消费者”模型为依据,提供了一个多线程的“生产者-消费者”实例,编写java代码调试运行结果,得出相应的结论。

理解矩阵乘法的实验步骤四、具体实现1.生产者-消费者实例(1)创建一个缓冲信息发送接收通道接口,并创建邮箱盒子类实现,主要代码如下://通道接口public interface Channelpublic abstract void send(Object item);public abstract Object receive();}//实现接口public class MessageQueue implements Channel{private Vector queue;public MessageQueue(){queue=new Vector();}public void send(Object item){queue.addElement(ite m);}public Object receive(){if(queue.size()==0)return null;elsereturn queue.remove(0);}}(2)创建一个工厂多线程类(启动生产者和消费者),并且添加main函数进行测试,主要代码如下://工厂类与主方法public class Factory{public Factory(){Channel mailBox=new MessageQueue();Thread producerThread=new Thread(newProducer(mailBox));Thread consumerThread=new Thread(newConsumer(mailBox));producerThread.start();consumerThread.start();}public static void main(String[] args)Factory server=new Factory();}(3)创建一个线程睡眠类,用于测试,主要代码如下:public class SleepUtilities{public static void nap(){nap(NAP_TIME);}public static void nap(int duration){int sleeptime = (int)(NAP_TIME * Math.random());try{ Thread.sleep(sleeptime*1000); }catch (InterruptedException e) {}}private static final int NAP_TIME = 5;(4)创建生产者类实现Runnable,主要代码如下:public class Producer implements Runnable{private Channel mbox;public Producer(Channel mbox){this.mbox=mbox;}public void run(){Date message;while(true){SleepUtilities.nap();message=new Date();System.out.println("Producer produced "+message);mbox.send(message);}}}(5)创建消费者类实现Runnable,主要代码如下:public class Consumer implements Runnable{private Channel mbox;public Consumer(Channel mbox){this.mbox=mbox;}public void run(){Date message;while(true){SleepUtilities.nap();message=(Date)mbox.receive();if(message!=null)System.out.println("Consumer consumed "+message);}}}(6)调试程序,运行结果:2.矩阵乘法实例(1)初始化矩阵(便于观察,这里使用随机数生成矩阵),主要初始化代码如下matrix1 = new int[m][k];matrix2 = new int[k][n];matrix3 = new int[m][n];//随机初始化矩阵a,bfillRandom(matrix1);fillRandom(matrix2);static void fillRandom(int[][] x){for (int i=0; i<x.length; i++){for(int j=0; j<x[i].length; j++){//每个元素设置为0到99的随机自然数x[i][j] = (int) (Math.random() * 100);}}}(2)打印输出矩阵函数,主要代码如下:static void printMatrix(int[][] x){for (int i=0; i<x.length; i++){for(int j=0; j<x[i].length; j++){System.out.print(x[i][j]+" ");}System.out.println("");}System.out.println("");}(3)创建多线程类,并实现Runnable接口同步对矩阵进行分行计算,主要代码如下://创建线程,数量 <= 4for(int i=0; i<4; i++){if(index < m){Thread t = new Thread(new MyThread());t.start();}else{break;}synchronized static int getTask(){if(index < m){return index++;}return -1;}}class MyThread implements Runnable{int task;//@Overridepublic void run(){MultiThreadMatrix.threadCount++;while( (task = MultiThreadMatrix.getTask()) != -1 ) {System.out.println("进程:"+Thread.currentThread().getName()+"\t开始计算第"+(task+1)+"行");for(int i=0; i<MultiThreadMatrix.n; i++) {for(int j=0; j<MultiThreadMatrix.k; j++) {MultiThreadMatrix.matrix3[task][i] +=MultiThreadMatrix.matrix1[task][j] *MultiThreadMatrix.matrix2[j][i];}}}MultiThreadMatrix.threadCount--;}(4)通过不断改变矩阵大小,线程数目,,调试程序,运行结果:五、所遇问题与解决方法1.在生产者-消费者多线程试验中,刚开始没有考虑到使用线程睡眠,运行结果速度之快,没法观看数据变化,后面定义了睡眠控制,使得问题得以解决2.在多线程矩阵开发实验中,刚开始定义矩阵太小,测试结果不太明显,后面通过把矩阵改大,并且线程数目不断变化使得结果明显。

操作系统中的经典问题——生产者消费者问题(两种方式实现)

操作系统中的经典问题——生产者消费者问题(两种方式实现)

操作系统中的经典问题——⽣产者消费者问题(两种⽅式实现)操作系统中的经典问题——⽣产者消费者问题(两种⽅式实现)1、问题引⼊:什么是⽣产者消费者问题?⽣产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是⼀个多线程同步问题的经典案例。

该问题描述了共享固定⼤⼩缓冲区的两个线程——即所谓的“⽣产者”和“消费者”——在实际运⾏时会发⽣的问题。

⽣产者的主要作⽤是⽣成⼀定量的数据放到缓冲区中,然后重复此过程。

与此同时,消费者也在缓冲区消耗这些数据。

该问题的关键就是要保证⽣产者不会在缓冲区满时加⼊数据,消费者也不会在缓冲区中空时消耗数据。

.要解决该问题,就必须让⽣产者在缓冲区满时休眠(要么⼲脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,⽣产者才能被唤醒,开始往缓冲区添加数据。

同样,也可以让消费者在缓冲区空时进⼊休眠,等到⽣产者往缓冲区添加数据之后,再唤醒消费者。

通常采⽤进程间通信的⽅法解决该问题。

如果解决⽅法不够完善,则容易出现死锁的情况。

出现死锁时,两个线程都会陷⼊休眠,等待对⽅唤醒⾃⼰。

该问题也能被推⼴到多个⽣产者和消费者的情形。

2、问题分析该问题需要注意的⼏点:1. 在缓冲区为空时,消费者不能再进⾏消费2. 在缓冲区为满时,⽣产者不能再进⾏⽣产3. 在⼀个线程进⾏⽣产或消费时,其余线程不能再进⾏⽣产或消费等操作,即保持线程间的同步4. 注意条件变量与互斥锁的顺序由于前两点原因,因此需要保持线程间的同步,即⼀个线程消费(或⽣产)完,其他线程才能进⾏竞争CPU,获得消费(或⽣产)的机会。

对于这⼀点,可以使⽤条件变量进⾏线程间的同步:⽣产者线程在product之前,需要wait直⾄获取⾃⼰所需的信号量之后,才会进⾏product的操作;同样,对于消费者线程,在consume之前需要wait直到没有线程在访问共享区(缓冲区),再进⾏consume的操作,之后再解锁并唤醒其他可⽤阻塞线程。

利用JAVA多线程并发机制解决生产者—消费者问题

利用JAVA多线程并发机制解决生产者—消费者问题
Ch n Yl e
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

C语言之生产者与消费者模型

C语言之生产者与消费者模型

C语⾔之⽣产者与消费者模型多线程并发应⽤程序有⼀个经典的模型,即⽣产者/消费者模型。

系统中,产⽣消息的是⽣产者,处理消息的是消费者,消费者和⽣产者通过⼀个缓冲区进⾏消息传递。

⽣产者产⽣消息后提交到缓冲区,然后通知消费者可以从中取出消息进⾏处理。

消费者处理完信息后,通知⽣产者可以继续提供消息。

要实现这个模型,关键在于消费者和⽣产者这两个线程进⾏同步。

也就是说:只有缓冲区中有消息时,消费者才能够提取消息;只有消息已被处理,⽣产者才能产⽣消息提交到缓冲区。

我们⽤⼀个队列来做这个缓冲区,产⽣的消息我们放到这个队列中去,如果这个队列满了,则不放⼊消息,我们这个队列⼤⼩是10,能够存放10条消息。

然后消费者去消费,消费者去这个缓冲区⾥去取数据,同样,如果缓冲区⾥没有数据,那么就不会消费。

这⼀模型的核⼼就是消费者和⽣产者⼀起去抢互斥锁,谁抢到了这个锁谁就有资格对这个缓冲区进⾏相关操作。

分析 ⼀线程负责⽣产数据,另⼀部分线程负责消费数据。

问题1:如果产⽣的块,消费的慢,⽣产者容易饿死 问题2:如果⽣产的慢,消费的快,消费者容易饿死 只有把两个问题协调好,才能最⼤限度的提⾼效率。

代码:#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <unistd.h>#define MAX 20char storage[MAX] = {};int count = 0;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t full = PTHREAD_COND_INITIALIZER;pthread_cond_t empty = PTHREAD_COND_INITIALIZER;void show_storage(char* role,char* op,char prod){printf("%s:",role);for(int i=0; i<count; i++){printf("%c",storage[i]);}printf("%s%c\n",op,prod);}void* pro_run(void* arg){char* who = "⽣产者";while(1){pthread_mutex_lock(&mutex);while(count >= MAX){printf("%s:满仓\n",who);pthread_cond_wait(&full,&mutex);}char prod = 'A'+rand()%26;storage[count++] = prod;show_storage(who,"->",prod);pthread_cond_signal(&empty);pthread_mutex_unlock(&mutex);usleep(rand()%100*1000);}}void* con_run(void* arg){char* who = "消费者";while(1){pthread_mutex_lock(&mutex);while(count <= 0){printf("%s:空仓\n",who);pthread_cond_wait(&empty,&mutex);}char prod = storage[count--];show_storage(who,"<-",prod);pthread_cond_signal(&full);pthread_mutex_unlock(&mutex);usleep(rand()%100*1000);}}int main(){pthread_t tid1,tid2;pthread_create(&tid1,NULL,pro_run,NULL); pthread_create(&tid2,NULL,con_run,NULL); getchar();}实现:。

多线程常考的算法题

多线程常考的算法题

多线程常考的算法题
多线程算法题常常考察对并行处理和线程同步的理解。

以下是一些常考的多线程算法题:
1.筷子原理(或称二叉堆栈):有两个栈,它们共享一段连续的内存。

这两个栈的指针分别为high 和low,每次操作都需要两个栈的指针进行比较,然后移动指针。

请设计一个线程安全的筷子算法。

2.生产者消费者问题:生产者生产物品放入缓冲区,消费者从缓冲区取出物品。

当缓冲区满时,生产者需要等待消费者取出物品;当缓冲区为空时,消费者需要等待生产者放入物品。

如何用多线程解决此问题?
3.栅栏问题:有一串数列,你可以把它想象成一排栅栏,每次只能向右移动一位,求最少多少次可以移动到最右边。

如何用多线程加速求解?
4.银行家算法:银行家算法是一种避免死锁的资源调度算法。

假设有多个进程请求资源,如何用多线程实现银行家算法?
5.线程池问题:如何设计一个线程池,使得任务队列不会溢出,并且能够充分利用多核资源?
6.锁的粒度问题:如何选择合适的锁粒度来平衡线程安全和性能?
7.读写锁问题:如何使用读写锁实现一个线程安全的缓存系统?
8.死锁检测与恢复:如何检测一个多线程系统中的死锁,并在检测到死锁后如何恢复?
9.线程同步问题:如何使用信号量、互斥锁等工具实现线程同步?
10.分布式系统中的一致性问题:如何在分布式系统中实现强一致性?
以上是一些常见的多线程算法题,通过解决这些问题,可以加深对多线程并行处理和线程同步的理解。

多线程 项目 经典案例

多线程 项目 经典案例

多线程项目经典案例
1. 生产者和消费者模型:一个经典的多线程项目案例是生产者和消费者模型。

该项目中有两类线程,分别是生产者线程和消费者线程。

生产者线程负责生成产品,并将产品放入一个共享的缓冲区中,而消费者线程则负责从缓冲区中取出产品进行消费。

2. 银行取款模型:在这个多线程项目中,会有多个用户同时通过ATM机进行取款操作。

每个用户都是一个线程,通过并行执行的方式进行取款操作。

为了避免多个用户同时从某一账户中取款而导致数据不一致的问题,需要使用同步机制来保护共享数据。

3. 图片下载器:该项目中有一个线程负责下载网络上的图片,并将下载完成的图片保存在本地。

同时,每当有图片下载完成后,会通知另一个线程更新界面,以显示下载进度和已完成的图片。

4. 多线程爬虫:这是一个经典的多线程项目案例,通过多线程的方式来实现对网站的并行爬取。

每个线程负责爬取不同的网页,并将爬取结果存储起来,最后合并所有结果。

5. 多线程排序:这个项目中,一个线程负责生成一组随机数,而其他线程则负责对这组随机数进行排序。

可以使用不同的排序算法,比如冒泡排序、插入排序、选择排序等。

每个线程独立地对一部分数据进行排序,最后将各个线程的排序结果进行合并。

6. 多线程游戏:在一个多线程游戏项目中,可以有多个线程同时进行游戏逻辑的处理,比如玩家移动、攻击、技能释放等。

每个线程负责不同的游戏逻辑,通过并行执行来提高游戏的并发性和响应速度。

producer consumer 设计模式

producer consumer 设计模式

producer consumer 设计模式生产者消费者设计模式是一种多线程设计模式,用于解决生产者和消费者之间的同步和通信问题。

此设计模式基于一个共享缓冲区,生产者向缓冲区中放入数据,消费者从缓冲区中取出数据。

此设计模式能够保证生产者和消费者的同步,避免生产者在缓冲区已满时继续生产,消费者在缓冲区为空时继续消费的问题。

在生产者消费者设计模式中,有以下几个核心角色:1. 生产者:负责生成数据,并将数据放入缓冲区。

2. 消费者:负责从缓冲区中取出数据并进行消费。

3. 缓冲区:共享的数据结构,用于存储生产者生成的数据,以及供消费者取出的数据。

4. 消费者队列:一个队列用于存放等待消费者消费的数据。

5. 信号量:用于控制生产者和消费者的访问权限。

当缓冲区已满时,生产者需要等待信号量;而当缓冲区为空时,消费者需要等待信号量。

6. 锁:用于确保同时只有一个线程能够访问共享资源。

以下是生产者消费者设计模式的基本实现步骤:1. 初始化缓冲区、信号量和锁。

2. 创建生产者线程和消费者线程,并启动它们。

3. 生产者线程生成数据,并将数据放入缓冲区。

如果缓冲区已满,生产者线程会等待信号量。

4. 消费者线程从缓冲区中取出数据并进行消费。

如果缓冲区为空,消费者线程会等待信号量。

5. 当生产者线程将数据放入缓冲区后,释放信号量,允许消费者线程继续。

6. 当消费者线程从缓冲区中取出数据后,释放信号量,允许生产者线程继续。

通过使用生产者消费者设计模式,可以有效地解决多线程环境下的数据同步和通信问题,确保生产者和消费者之间的合作顺利进行。

多线程 经典题目

多线程 经典题目

多线程经典题目多线程经典题目主要涉及多线程编程的基本概念、同步机制、线程池、并发编程等方面。

以下是一些典型的多线程经典题目:1. 创建一个多线程程序,实现交替打印字符。

可以使用synchronize 同步锁、lock 锁、concurrent 的默认机制、volatile 关键字、Thread.sleep()/Thread.yield 机制、atomic 原子类等方式实现。

2. 实现一个多线程程序,打印0 和奇偶数字。

可以使用锁(sychronized 和Lock)、并发工具(barrier、semaphore)、CAS、Thread.sleep()/volatile、blocking queue 等方式实现。

3. 设计一个生产者-消费者问题的多线程程序。

可以使用ReentrantLock、full 和empty 对象、死循环等方式实现。

4. 实现一个哲学家进餐问题的多线程程序。

一个经典的并发控制问题,通过筷子数量和状态来控制哲学家的就餐行为。

5. 实现一个读者-写者问题的多线程程序。

使用两个锁(readerLock 和writerLock)来控制读写操作。

6. 设计一个多线程并发统计文件夹内关键字频率的程序。

可以使用线程池和Future 进行文件夹内关键字统计。

7. 实现一个多线程爬虫程序,爬取网页信息并处理。

可以使用线程池、并发集合等技术进行优化。

8. 设计一个多线程网络通信程序,实现客户端与服务器的通信。

可以使用阻塞IO、非阻塞IO、异步IO 等方式实现。

以上是一些典型的多线程经典题目,可以帮助你更好地理解和掌握多线程编程的基本知识和应用。

在实际编程过程中,多线程编程可能会遇到死锁、竞争条件、活锁等问题,需要根据具体场景选择合适的同步机制和线程池大小等参数来避免这些问题。

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

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

Java实现⽣产者消费者问题与读者写者问题摘要: Java实现⽣产者消费者问题与读者写者问题1、⽣产者消费者问题⽣产者消费者问题是研究多线程程序时绕不开的经典问题之⼀,它描述是有⼀块缓冲区作为仓库,⽣产者可以将产品放⼊仓库,消费者则可以从仓库中取⾛产品。

解决⽣产者/消费者问题的⽅法可分为两类:(1)采⽤某种机制保护⽣产者和消费者之间的同步;(2)在⽣产者和消费者之间建⽴⼀个管道。

第⼀种⽅式有较⾼的效率,并且易于实现,代码的可控制性较好,属于常⽤的模式。

第⼆种管道缓冲区不易控制,被传输数据对象不易于封装等,实⽤性不强。

同步问题核⼼在于:如何保证同⼀资源被多个线程并发访问时的完整性。

常⽤的同步⽅法是采⽤信号或加锁机制,保证资源在任意时刻⾄多被⼀个线程访问。

Java语⾔在多线程编程上实现了完全对象化,提供了对同步机制的良好⽀持。

在Java中⼀共有五种⽅法⽀持同步,其中前四个是同步⽅法,⼀个是管道⽅法。

wait() / notify()⽅法await() / signal()⽅法BlockingQueue阻塞队列⽅法Semaphore⽅法PipedInputStream / PipedOutputStream1.1 wait() / notify()⽅法wait() / nofity()⽅法是基类Object的两个⽅法,也就意味着所有Java类都会拥有这两个⽅法,这样,我们就可以为任何对象实现同步机制。

wait()⽅法:当缓冲区已满/空时,⽣产者/消费者线程停⽌⾃⼰的执⾏,放弃锁,使⾃⼰处于等等状态,让其他线程执⾏。

notify()⽅法:当⽣产者/消费者向缓冲区放⼊/取出⼀个产品时,向其他等待的线程发出可执⾏的通知,同时放弃锁,使⾃⼰处于等待状态。

各起了4个⽣产者,4个消费者package test;public class Hosee {private static Integer count = 0;private final Integer FULL = 10;private static String LOCK = "LOCK";class Producer implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10; i++) {try {Thread.sleep(3000);} catch (Exception e) {e.printStackTrace();}synchronized (LOCK) {while (count == FULL) {try {LOCK.wait();} catch (Exception e) {e.printStackTrace();}}count++;System.out.println(Thread.currentThread().getName() + "⽣产者⽣产,⽬前总共有" + count);LOCK.notifyAll();}}}}class Consumer implements Runnable {@Overridepublic void run() {Thread.sleep(3000);} catch (InterruptedException e1) {e1.printStackTrace();}synchronized (LOCK) {while (count == 0) {try {LOCK.wait();} catch (Exception e) {}}count--;System.out.println(Thread.currentThread().getName() + "消费者消费,⽬前总共有" + count);LOCK.notifyAll();}}}}public static void main(String[] args) throws Exception {Hosee hosee = new Hosee();new Thread(hosee.new Producer()).start();new Thread(hosee.new Consumer()).start();new Thread(hosee.new Producer()).start();new Thread(hosee.new Consumer()).start();new Thread(hosee.new Producer()).start();new Thread(hosee.new Consumer()).start();new Thread(hosee.new Producer()).start();new Thread(hosee.new Consumer()).start();}}(需要注意的是,⽤什么加锁就⽤什么notify和wait,实例中使⽤的是LOCK)部分打印结果:由于⽣产者和消费者说明⼀致,所以最多都是在2左右,当减少⼀个消费者时,则会加到10。

基于信号量的生产者消费同步问题

基于信号量的生产者消费同步问题

基于信号量的生产者消费同步问题一、实验目的了解Windows中的进程和线程,了解多线程编程,理解基于信号量的线程同步的实现,实现生产者消费者同步问题。

二、实验环境Windows操作系统Visual Status编程环境三、实验要求跟着实验指导书步骤边做边思考,同时完成实验报告(非正式,无格式要求,但须按指导书要求列出相关内容)。

四、实验内容与步骤:1、查阅有关函数并理解参数含义HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCTSTR lpName);函数说明:第一个参数表示安全控制,一般直接传入NULL。

第二个参数表示信号量计数器初始值(初始资源数量)。

第三个参数表示信号量计数器最大值(最大并发数量)。

第四个参数表示信号量的名称,传入NULL表示匿名信号量。

2、线程同步:简化的生产者消费者问题(缓冲区1个,生产者1个,消费者1个)1)调整生产者和消费者速度,看看能否真正实现生产者和消费者同步?2)将实验结果写入实验报告。

3、进程同步:简单生产者消费者问题:编写生产者进程程序:编写消费者进程程序:1)请将实验结果写入实验报告。

2)调整生产者和消费者速度,看看能否真正实现生产者进程和消费者进程同步?3)请问在生产者进程和消费者进程程序中信号量的命名为什么必须保持一致?如果不一致能否得到期望结果?3、经典生产者消费者问题(有多个缓冲区构成缓冲池)。

1)请将实验结果写入实验报告中。

2)生产者线程请求hSemEmpty信号量和请求hMutex信号量的次序能否调换?消费者线程请求hSemFull信号量和请求hMutex信号量的次序能否调换?为什么?2)如果有多个生产者和多个消费者,如何改写该同步演示程序?。

两种解决生产者—消费者问题的Java实现模型

两种解决生产者—消费者问题的Java实现模型

并 且在 Jv . aa中 可采 用 sn ho i d或 O jc 类 的 方 y crnz e b t e 法 w i )n ty )r ty l ) 实现 多线程 同步 。 at ,oi ( ,oi Al 来 ( f  ̄f ( Jv 线茬 同 步机 制 的实 现是 基 于管 程 ( n. aa多 Mo i
() 2 生产 者一 费者 问题 的解 决模型 与 I a实现 消 a v


在下 面 的 Jv a a应用 程序 中 .生 产者线 程 向缓 冲
o OENC PT , MDR O UE 6 M R
维普资讯
实 践 与 经 验
区中写数据 , 费者从缓 冲 区中读数 据 , 消 这样 , 在这个 程序 中同时运行 的多个线 程竞 争 同一 个缓 冲区 资源 。 类 Po ue 是 生 产者 模 型 , 中的 rn ) rd cr 其 u f 方法 中定义 了生产者线 程所做 的操作 . 环地将 生产 的“ 品” 循 产 放 入缓 冲区 中 , 每次 生产完 后 。 用 s e f 方 法睡 眠一 调 l p) e 段随机时 间 , 以给其他线 程执 行的机会 。类 C nu r o sme
维普资讯
安 践 与 经 验
范 容 . 胡 则辉
( 杭州 师范学 院信息 工程 学院 . 杭州 3 0 1 ) 10 8

要 : 文 以Jv 的 多线程机 制为技 术手段 , 拟 了经典 的生 产者 消费者 问题 , 本 aa 模 解决 了此 问题 中 的 同步 问题 。
产 者 p 生产 的产 品就 可 以投入 缓 冲 区 ; 似地 , i 类 只要
现 代 计


多线程同步的四种方式(史上最详细+用例)

多线程同步的四种方式(史上最详细+用例)

多线程同步的四种⽅式(史上最详细+⽤例)多线程同步的四种⽅式对于多线程程序来说,同步是指在⼀定的时间内只允许某⼀个线程来访问某个资源。

⽽在此时间内,不允许其他的线程访问该资源。

可以通过互斥锁(Mutex)、条件变量(condition variable)、读写锁(reader-writer lock)、信号量(semaphore)来同步资源。

1. 互斥锁(Mutex)互斥量是最简单的同步机制,即互斥锁。

多个进程(线程)均可以访问到⼀个互斥量,通过对互斥量加锁,从⽽来保护⼀个临界区,防⽌其它进程(线程)同时进⼊临界区,保护临界资源互斥访问。

互斥锁需要满⾜三个条件:互斥不同线程的临界区没有重叠⽆死锁如果⼀个线程正在尝试获得⼀个锁,那么总会成功地获得这个锁。

若线程A调⽤lock()但是⽆法获得锁,则⼀定存在其他线程正在⽆穷次地执⾏临界区。

⽆饥饿每⼀个试图获得锁的线程最终都能成功。

#include <stdio.h>#include <stdlib.h>#include <pthread.h>void *function(void *arg);pthread_mutex_t mutex;int counter = 0;int main(int argc, char *argv[]){int rc1,rc2;char *str1="hello";char *str2="world";pthread_t thread1,thread2;pthread_mutex_init(&mutex,NULL);if((rc1 = pthread_create(&thread1,NULL,function,str1))){fprintf(stdout,"thread 1 create failed: %d\n",rc1);}if(rc2=pthread_create(&thread2,NULL,function,str2)){fprintf(stdout,"thread 2 create failed: %d\n",rc2);}pthread_join(thread1,NULL);pthread_join(thread2,NULL);return 0;}void *function(void *arg){char *m;m = (char *)arg;pthread_mutex_lock(&mutex);while(*m != '\0'){printf("%c",*m);fflush(stdout);m++;sleep(1);}printf("\n");pthread_mutex_unlock(&mutex);}2. 条件变量(condition variable)⽣产者消费者问题:每次⽣产⼀个商品,发⼀个信号,告诉消费者“我⽣产商品了,快来消费”,消费者拿到⽣产者的条件变量后每次消费两个商品,然后发出信号“我消费了商品,你可以⽣产了”--_--(发的这个信号是⼀个条件变量,通过发送这个信号可以唤醒阻塞的线程,收到信号后,不满⾜需求也会继续阻塞)为了防⽌竞争,条件变量的使⽤总是和⼀个互斥锁结合在⼀起;条件变量是线程的另⼀种同步机制,它和互斥量是⼀起使⽤的。

生产者与消费者算法

生产者与消费者算法

生产者与消费者算法1. 简介生产者与消费者算法是操作系统中一种解决生产者与消费者问题的经典算法。

生产者与消费者问题是指多个生产者和多个消费者共享一个有限缓冲区,生产者向缓冲区中放入数据,消费者从缓冲区中取出数据的问题。

生产者与消费者算法通过合理地同步生产者与消费者的操作,保证生产者和消费者的正确性和公平性。

本文将介绍生产者与消费者算法的原理、实现和使用方法。

2. 原理生产者与消费者算法的核心思想是使用互斥锁和条件变量。

互斥锁用于保护共享缓冲区的访问,条件变量用于实现生产者和消费者之间的等待和唤醒操作。

具体来说,算法包括以下几个步骤:1.定义共享缓冲区,并初始化相关变量(如指针、计数器等)。

2.创建互斥锁和条件变量,并初始化。

3.同时启动多个生产者线程和消费者线程。

4.生产者线程的主要工作是生产数据并将其放入缓冲区中。

在放入数据之前,需要获取互斥锁进行保护。

5.消费者线程的主要工作是从缓冲区中取出数据并进行消费。

在取出数据之前,需要获取互斥锁进行保护。

6.若缓冲区已满,生产者线程需要等待条件变量唤醒。

7.若缓冲区为空,消费者线程需要等待条件变量唤醒。

8.当生产者线程放入数据后,需唤醒等待中的消费者线程;当消费者线程取出数据后,需唤醒等待中的生产者线程。

9.在线程操作结束后,释放互斥锁。

3. 实现以下是一个简单的生产者与消费者算法的示例代码。

代码使用了C语言的pthread库实现多线程。

```c #include <stdio.h> #include <stdlib.h> #include <pthread.h>#define BUFFER_SIZE 5 // 缓冲区大小int buffer[BUFFER_SIZE]; // 共享缓冲区 int in = 0; // 指示下一个生产者放置数据的位置 int out = 0; // 指示下一个消费者取出数据的位置pthread_mutex_t mutex; // 互斥锁 pthread_cond_t full; // 缓冲区满条件变量pthread_cond_t empty; // 缓冲区空条件变量void producer(void arg) { int data = 0; while (1) { pthread_mutex_lock(&mutex); while ((in + 1) % BUFFER_SIZE == out) { pthread_cond_wait(&full, &mutex); }buffer[in] = data; in = (in + 1) % BUFFER_SIZE; data++;pthread_cond_signal(&empty); pthread_mutex_unlock(&mutex); } }void consumer(void arg) { while (1) { pthread_mutex_lock(&mutex); while (in == out) { pthread_cond_wait(&empty, &mutex); } int data = buffer[out]; out = (out + 1) % BUFFER_SIZE; printf(。

Java线程实现Redis任务队列(生产者消费者)

Java线程实现Redis任务队列(生产者消费者)

Java线程实现Redis任务队列(生产者消费者)Redis是一种开源的高性能键值存储数据库,常用于缓存、消息队列和任务队列等场景。

在Java中,我们可以利用Redis实现一个简单的任务队列,使用多线程来实现生产者消费者模式。

在Java中,可以使用Jedis库与Redis进行交互。

首先,我们需要引入Jedis库的依赖,例如通过Maven引入以下依赖项:```xml<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version></dependency>```接下来,我们可以创建一个生产者类和一个消费者类来实现任务队列。

```javaimport redis.clients.jedis.Jedis;public class Producer implements Runnableprivate Jedis jedis;private String queueName;this.jedis = jedis;this.queueName = queueName;}public void rufor (int i = 0; i < 10; i++)String task = "Task " + i;jedis.rpush(queueName, task);System.out.println("Produced task: " + task); tryThread.sleep(1000);} catch (InterruptedException e)e.printStackTrace(;}}}public class Consumer implements Runnable private Jedis jedis;private String queueName;this.jedis = jedis;this.queueName = queueName;}public void ruwhile (true)List<String> tasks = jedis.blpop(0, queueName); String task = tasks.get(1);System.out.println("Consumed task: " + task); tryThread.sleep(2000);} catch (InterruptedException e)e.printStackTrace(;}}}```在生产者类中,我们使用`jedis.rpush(queueName, task)`方法将任务推送到Redis的列表中。

消费者生产者问题

消费者生产者问题

北方民族大学课程设计报告系(部、中心)计算机科学与工程学院姓名杨和平学号 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个整型数。

试修改下面生产者—消费者问题解法中的错误(信号量mutex的初值为1,信号量empty的

试修改下面生产者—消费者问题解法中的错误(信号量mutex的初值为1,信号量empty的

试修改下面生产者—消费者问题解法中的错误(信号量mutex的初值为1,信号量empty的生产者-消费者问题:1. 介绍生产者—消费者问题(Producer-Consumer Problem)是多线程编程中,一种常见的线程同步问题,也是一种临界资源共享问题,因此也被称作生产者-消费者问题,它可以用来描述并发线程的安全访问和同步的问题。

2. 背景生产者—消费者问题一般描述如下:存在一个有容量的buffer,多个producer通过放置产品到buffer中,把buffer填满,每个producer都有自己的能力,可以生产出一条货物,而多个consumer也可以从buffer中提取货物,以消耗buffer中的货物。

3. 传统解法传统解法基于信号量进行控制,通常情况下,需要两个信号量mutex和empty , mutex 保证buffer中只有一个生产者或者一个消费者,empty 的初值位buffer的容量,当一个生产者有了新的产物,会将empty 的值-1,而当一个消费者提取了一个产物,会将empty 的值+1 。

4. 错误现象在实际的生产者—消费者问题中,经常出现信号量mutex的初始值为1,信号量empty的初始值为0,这时候就可能出现阻塞情况,因为生产者可能会在某一时刻被锁住导致无法继续工作,进而导致消费者一直消耗不及生产,无法使得系统运行成功。

5. 优化策略一种常用的解决方案是在准备阶段,保证信号量mutex和empty的初始值满足:mutex=1, empty>0的条件。

此外,在生产者与消费者的执行阶段,通过一定的算法控制其访问buffer的次数,以保证能够容纳所有的生产者和消费者,以达到完美的运行效果。

6. 总结综上所述,生产者—消费者问题是一种多线程编程中,常见的线程同步与资源共享问题,若不完整理解其原理和该问题本身,在实践时很容易出现同步错误,形成死锁。

一种优化的解决方法是在准备阶段,保证信号量mutex和empty的初始值满足:mutex=1,empty>0的条件,并在生产者与消费者的执行阶段,通过一定的算法进行配合,才能让系统安全运行。

生产者消费者模式

生产者消费者模式

生产者消费者模式生产者消费者模式是一种常见的并发编程模式,用于解决在多线程环境下生产者和消费者之间的协同问题。

在该模式中,生产者负责生成数据,并将数据放入共享的缓冲区中,而消费者则从缓冲区中取出数据并进行处理。

通过合理地安排生产者和消费者的执行,可以实现数据的有序生成和消耗,避免资源的竞争和互斥现象,从而提高系统的效率和吞吐量。

生产者消费者模式的设计思想源于现实生活中的生产与消费过程。

在现实生活中,生产者负责生产商品,而消费者则负责购买和消费商品。

一般来说,生产者和消费者之间是相互独立的,生产者可以独立地进行生产,而消费者可以独立地进行消费。

然而,在某些情况下,生产者和消费者之间存在一定的联系和依赖关系。

在多线程编程中,生产者消费者模式的主要目的是解决生产者和消费者线程之间的同步问题。

当生产者生成数据并放入缓冲区时,需要确保消费者线程能够及时获取到数据并进行处理。

反之,当缓冲区为空时,消费者线程需要等待生产者生成新的数据。

为了实现生产者和消费者之间的协同,可以使用一些同步机制,如信号量、互斥锁、条件变量等。

在生产者消费者模式中,有三个主要的角色:生产者、消费者和缓冲区。

生产者负责生成数据,并将数据放入缓冲区中。

消费者则从缓冲区中取出数据并进行处理。

缓冲区充当了生产者和消费者之间的中介角色,用于存储生产者生成的数据,以及提供给消费者进行获取。

在实际应用中,生产者消费者模式可以用于解决多线程环境下的资源管理问题。

比如,在一个网络服务器程序中,可能存在多个客户端同时请求数据的情况。

这时,可以使用生产者消费者模式来管理网络请求的处理。

生产者线程负责接收客户端请求,并将请求放入请求队列中。

消费者线程则从请求队列中取出请求,并进行相应的处理和响应。

通过合理地设计和使用生产者消费者模式,可以有效地提高系统的并发处理能力。

总之,生产者消费者模式是一种常见的并发编程模式,通过合理安排生产者和消费者线程的执行顺序,可以实现数据的有序生成和消耗,提高系统的效率和吞吐量。

生产者和消费者问题实验报告

生产者和消费者问题实验报告

格式: 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.掌握进程(线程)的同步与互斥。

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. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

目录1.需求分析 (1)1.1 课程设计题目 (1)1.2 课程设计任务 (1)1.3 课程设计原理 (1)1.4 课程设计要求 (1)1.5 实验环境 (1)2. 概要设计 (2)2.1 课程设计方案概述 (2)2.2 课程设计流程图 (2)3.详细设计 (3)3.1 主程序模块 (3)3.2 生产者程序模块 (4)3.3 消费者程序模块 (5)4.调试中遇到的问题及解决方案 (5)5.运行结果 (6)6.实验小结 (7)参考文献 (7)附录:源程序清单 (7)1.需求分析1.1 课程设计题目用多线程同步方法解决生产者-消费者问题1.2 课程设计任务(1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容、当前指针位置和生产者/消费者线程的标识符。

(2)生产者和消费者各有两个以上。

(3)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。

1.3 课程设计原理生产者和消费者问题是从操作系统中的许多实际同步问题中抽象出来的具有代表性的问题,它反映了操作系统中典型的同步例子,生产者进程(进程由多个线程组成)生产信息,消费者进程使用信息,由于生产者和消费者彼此独立,且运行速度不确定,所以很可能出现生产者已产生了信息而消费者却没有来得及接受信息这种情况。

为此,需要引入由一个或者若干个存储单元组成的临时存储区(即缓冲区),以便存放生产者所产生的信息,解决平滑进程间由于速度不确定所带来的问题。

1.4 课程设计要求(1)有界缓冲区内设有20个存储单元,放入/取出的数据项设定为1~20这20个整型数。

(2)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容、当前指针位置和生产者/消费者线程的标识符。

(3)生产者和消费者各有两个以上。

(4)多个生产者或多个消费者之间须共享对缓冲区进行操作的函数代码。

1.5 实验环境系统平台:LINUX开发语言:C开发工具:PC机一台2. 概要设计2.1 课程设计方案概述本设计中设置一个长度为20的一维数组buff[20]作为有界缓冲区,缓冲区为0时,代表该缓冲区内没有产品,buff[i]=i+1表示有产品,产品为i+1。

设置3个同步信号灯:一个说明空缓冲区的数目,用empty表示,其初值为有界缓冲区的大小20 ;另一个说明满缓冲区(即产品)的数目,用full表示,其初值为0。

由于缓冲区是临界资源,必须互斥使用,所以还设置了一个互斥信号灯mutex,其初值为1。

用这3个信号灯有效控制多个生产者线程和多个消费者线程的同步准确的运行。

Main()函数中调用函数sem_init()对信号灯进行初始化;利用for语句循环创建5个producer(生产者)分离线程和5个consumer(消费者)分离线程;Producer线程通过调用函数sem_wait(&empty)判断是否有空缓冲区。

若无,则阻塞当前线程,若有则调用函数sem_wait(&mutex)等待对临界资源的操作权,当mntex为1时,便获得临界资源的操作权,可将产品放入缓冲区,及时输出缓冲区里的内容。

然后依次调用函数sem_post(&mutex)和sem_post(&full)来释放缓冲区操作权和增加满缓冲区信号量的值;Consumer线程通过调用函数sem_wait(&full) 判断是否有满缓冲区。

若无,则阻塞当前线程,若有则调用函数sem_wait(&mutex)等待对临界资源的操作权,当mntex为1时,便获得临界资源的操作权,可从满缓冲区中取出产品消费,并及时输出缓冲区里的内容。

然后依次调用函数sem_post(&mutex)和sem_post(&emptyl)来释放缓冲区操作权和增加空满缓冲区信号量的值。

Producer和Consumer线程中均用缓冲区指针b指出当前是对哪一个缓冲区进行放入/取出操作;并调用pthread_self()函数来显示其自身的标识符。

2.2 课程设计流程图设计中主要有三个模块,首先从主程序中进入,完成初始化及创建好生产者和消费者线程后,进入生产者或消费者模块,具体流程见程序设计流程图如图1所示:生产者消费者3.详细设计3.1 主程序模块主程序中利用函数sem_init()对信号灯进行初始化;利用for语句循环创建3个producer(生产者)分离线程和3个consumer(消费者)分离线程,程序段如下:int main(void){ int i;initbuff();for(i=0;i<5;i++){pthread_create(&id1[i],NULL,(void *)producer,(&i));} //创建生产者线程for(i=0;i<5;i++){pthread_create(&id2[i],NULL,(void *)consumer,(&i));} //创建消费者线程for(i=0;i<5;i++){ pthread_join(id1[i],NULL);pthread_join(id2[i],NULL); }exit(0); } //等待生产者线程,消费者线程,结束主线程3.2 生产者程序模块Producer线程通过调用函数sem_wait(&empty)判断是否有空缓冲区。

若无,则阻塞当前线程,若有则调用函数sem_wait(&mutex)等待对临界资源的操作权,当mntex为1时,便获得临界资源的操作权,可将产品放入缓冲区,及时输出缓冲区里的内容;并用指针b指出当前是对哪一个缓冲区进行放入/取出操作,且调用pthread_self()函数来显示其自身的标识符。

然后依次调用函数sem_post(&mutex)和sem_post(&full)来释放缓冲区操作权和增加满缓冲区信号量的值,程序段如下:void producer() //生产者{ int pid=0;int j,k;pid=pthread_self(); //获得生产者标识符while(1){ for(j=0;j<5;j++){ if(pid==id1[j]){ k=j+1; } }sem_wait(&empty); //P操作,判断缓冲区是否有空位置sem_wait(&mutex); //P操作,获得对临界资源的操作权if(p%21!=0){ buff[b]=p%21;printf("producer %d produce:%d\n",k,p%21);printbuff();b++; p++; }else p++;sem_post(&mutex); //V操作,释放临界资源sem_post(&full); //V操作,满缓冲区信号灯加1sleep(4); } }3.3 消费者程序模块Consumer线程调用调用函数sem_wait(&full) 判断是否有满缓冲区。

若无,则阻塞当前线程,若有则调用函数sem_wait(&mutex)等待对临界资源的操作权,当mntex为1时,便获得临界资源的操作权,可从满缓冲区中取出产品消费,并及时输出缓冲区里的内容,并用指针b指出当前是对哪一个缓冲区进行放入/取出操作,且调用pthread_self()函数来显示其自身的标识符。

然后依次调用函数sem_post(&mutex)和sem_post(&emptyl)来释放缓冲区操作权和增加空满缓冲区信号量的值,程序段如下:void consumer() //消费者{ int cid=0;int j,k;cid=pthread_self(); //获得消费者标识符while(1){ for(j=0;j<5;j++){ if(cid==id2[j]){ k=j+1; } }sem_wait(&full); //P操作,判断缓冲区是否已满sem_wait(&mutex); //P操作,获得对临界资源的操作权if(c%21!=0){ c1=buff[b-1];printf("consumer %d consume:%d\n",k,c1);buff[b-1]=0;printbuff();b--; c++; }else c++;sem_post(&mutex); //V操作,释放临界资源sem_post(&empty); //V操作,释放一个空位置sleep(6); }4.调试中遇到的问题及解决方案在调试过程中主要遇到三个问题:1.在设计刚完成的时候,我并没有用pid=pthread_self()和cid=pthread_self()来获得生产者和消费者的标识符,所以运行的结果是生产者和消费者的标识符都是随机的,后来问同学才找到这种调用方法。

2.我想让生产者无限的生产,消费者无限的消费,所以就用了一个条件判断语句,判断的条件是p%21!=0,而我写成了p/21!=0,所以运行的结果是生产者的生产是混乱的,没有规律。

3.刚开始我的运行结果还有一个问题就是生产者生产超过21的产品后,产品号不是1,2…等,而是21,22,…,后来检查后才发现printf("producer %d produce:%d\n",k,p%21)中的产品号不是p%21,所以出现那种情况。

5.运行结果显示结果如下:(部分运行结果)6.实验小结这次课程设计主要针对的是操作系统中的经典问题即:生产者——消费者问题使用多线程控制,刚拿到设计题目时心里其实挺没底的,因为之前我对线程不是很了解,不过幸好老师上课的时候给了我们一个关于Linux多线程编程的文档,里面详细的介绍了线程的一些基本命令,所以我在这次设计中基本上都用的是文档里的命令。

从这次课程设计中,我对线程的概念以及一些命令都有了一定的理解和掌握,并且也知道了它与进程之间的区别,除此之外,通过这次课程设计让我对操作系统中的经典问题,生产者——消费者问题有了更深的理解,在做设计的过程中,也对上课的内容加深了理解并进行了巩固。

参考文献[1]庞丽萍.操作系统原理.华中科技大学出版社.2009年1月。

[2] 蒋静徐志伟.操作系统原理技术与编程[M].北京:机械工业出版社,2004[3]张红光李福才.UNIX操作系统。

机械工业出版社。

2006年1月[4]汤子瀛等.计算机操作系统.西安电子科技大学出版社.2001年5月[5]付国瑜杨武周敏.计算机操作系统原理及应用上机实验指导.重庆工学院计算机学院.2005年1月.附录:源程序清单#include<stdio.h>#include<pthread.h>#include<stdlib.h>#include<semaphore.h>int buff[20]={0}; //有界缓冲区定义int b=0; //缓冲区的输出指针int p=1;int c=1;int c1=0; //消费数据变量sem_t full; //缓冲区的数量信号灯sem_t empty; //缓冲区满信号灯sem_t mutex; //互斥信号灯pthread_t id1[5];pthread_t id2[5];void initbuff() //初始化信号灯{ sem_init(&full,0,0);sem_init(&empty,0,20);sem_init(&mutex,0,1); //初始化互斥信号灯 } void printbuff() //打印缓冲区{ int j;printf("datas in buff are:");for(j=0;j<20;j++)printf("%d ",buff[j]);printf("\n"); }void producer() //生产者{ int pid=0;int j,k;pid=pthread_self();while(1){ for(j=0;j<5;j++){ if(pid==id1[j]){ k=j+1; } }sem_wait(&empty);sem_wait(&mutex);if(p%21!=0){ buff[b]=p%21;printf("producer %d produce:%d\n",k,p%21);printbuff();b++;p++; }else p++;sem_post(&mutex);sem_post(&full);sleep(4); } }void consumer() //消费者{ int cid=0;int j,k;cid=pthread_self();while(1){ for(j=0;j<5;j++){ if(cid==id2[j]){ k=j+1; } }sem_wait(&full); //看是否有数据在缓冲区sem_wait(&mutex); //临界区if(c%21!=0){ c1=buff[b-1];printf("consumer %d consume:%d\n",k,c1);buff[b-1]=0;printbuff();b--;c++; }else c++;sem_post(&mutex);sem_post(&empty);sleep(6); } }int main(void){ int i;initbuff();for(i=0;i<5;i++){pthread_create(&id1[i],NULL,(void *)producer,(&i));} //创建生产者线程 for(i=0;i<5;i++){pthread_create(&id2[i],NULL,(void *)consumer,(&i));} //创建消费者线程 for(i=0;i<5;i++){ pthread_join(id1[i],NULL);pthread_join(id2[i],NULL); }exit(0); } //等待生产者线程,消费者线程,结束主线程武汉理工大学华夏学院《操作系统原理》课程设计报告10。

相关文档
最新文档