操作系统课程设计生产者消费者
操作系统课程设计 生产者与消费者

燕山大学课程设计说明书课程设计名称:操作系统OS题目:多道程序缓冲区协调操作班级:开发小组名称:课题负责人:课题组成员:姓名学号班级自评成绩课题开发日期:一、概述利用MFC类库编写一个可实现多道程序缓冲区协调操作的面向对象的程序。
1.1基本功能演示生产者消费者程序,多线程并发执行的过程;可以控制生产者消费者的个数及生产者生产的速度和消费者的速度,进度条中显示Buffer 中数据的个数,有五个按钮,分别为:开始、继续,暂停、结束、退出,点击开始按钮,程序开始执行,点击暂停按钮,所有线程暂停执行,点击继续按钮,线程继续执行,结束按钮使得所有线程结束执行,点击退出按钮,退出系统,统计按钮按下时显示此时的Buffer1,buffer2的生产者生产的次数和Buffer3的消费者消费的次数,及Move的次数,和开始时间及结束时间。
1.2开发计划10号查阅参考资料,了解整体的框架结构; 11号完成整体模块的构思及设计; 12号完成程序具体的编写任务并调试代码; 13号整理总结并书写报告; 14号验收。
1.3人员分工1.4环境、工具和开发方法本程序在XP系统下,采用的开发语言是C++,它是一种使用非常广泛的面向对象的计算机编程语言。
它支持过程化程序设计、数据抽象、面向对象程序设计、制作图标等多种程序设计风格。
在Visual C++ 6.0编程环境中,利用MFC类库编写C++风格的应用程序,基于MFC类库的应用程序可以快速建立起应用程序,并且类库为我们提供了大量的封装类。
二、需求分析用户需要看到看到并发程序的运行过程,以及能对过程进行控制,可以设计几个按钮控制开始,暂停、结束等功能,并可以让用户自定义生产者消费者数量及生产者消费者线程并发执行的速度,并能以用户能够明白的形式表示出来,可以设计一个进度条显示各个Buffer中的物品数量,并用数字显示出来,看的就清楚了,设置一个统计按钮,当用户点击按钮时,就可以获取当前各个线程的情况,有几个线程在执行,Buffer1的线程个数,Buffer2的线程个数及从开始到结束所用的时间,从而了解线程运行的情况。
操作系统_生产者和消费者

《操作系统》课程设计生产者和消费者的问题学院:计算机学院学生姓名:屈杨学号:5409216018专业:计算机科学技术其中实验数据是:3附件:原程序代码#include<windows.h>#include<fstream.h>#include<stdio.h>#include<string>#include<conio.h>//定义一些常量;//本程序允许的最大临界区数;#define MAX_BUFFER_NUM 10//秒到微秒的乘法因子;#define INTE_PER_SEC 1000//本程序允许的生产和消费线程的总数;#define MAX_THREAD_NUM 64//定义一个结构,记录在测试文件中指定的每一个线程的参数struct ThreadInfo{int serial; //线程序列号char entity; //是P还是Cdouble delay; //线程延迟int thread_request[MAX_THREAD_NUM]; //线程请求队列int n_request; //请求个数};//全局变量的定义//临界区对象的声明,用于管理缓冲区的互斥访问;CRITICAL_SECTION PC_Critical[MAX_BUFFER_NUM];int Buffer_Critical[MAX_BUFFER_NUM]; //缓冲区声明,用于存放产品;HANDLE h_Thread[MAX_THREAD_NUM]; //用于存储每个线程句柄的数组;ThreadInfo Thread_Info[MAX_THREAD_NUM]; //线程信息数组;HANDLE empty_semaphore; //一个信号量;HANDLE h_mutex; //一个互斥量;DWORD n_Thread = 0; //实际的线程的数目;DWORD n_Buffer_or_Critical; //实际的缓冲区或者临界区的数目;HANDLE h_Semaphore[MAX_THREAD_NUM]; //生产者允许消费者开始消费的信号量;//生产消费及辅助函数的声明void Produce(void *p);void Consume(void *p);bool IfInOtherRequest(int);int FindProducePositon();int FindBufferPosition(int);int main(void){//声明所需变量;DWORD wait_for_all;ifstream inFile;//初始化缓冲区;for(int i=0;i< MAX_BUFFER_NUM;i++)Buffer_Critical[i] = -1;//初始化每个线程的请求队列;for(int j=0;j<MAX_THREAD_NUM;j++){for(int k=0;k<MAX_THREAD_NUM;k++)Thread_Info[j].thread_request[k] = -1;Thread_Info[j].n_request = 0;}//初始化临界区;for(i =0;i< MAX_BUFFER_NUM;i++)InitializeCriticalSection(&PC_Critical[i]);//打开输入文件,按照规定的格式提取线程等信息;inFile.open("test.txt");//从文件中获得实际的缓冲区的数目;inFile >> n_Buffer_or_Critical;inFile.get();printf("输入文件是:\n");//回显获得的缓冲区的数目信息;printf("%d \n",(int) n_Buffer_or_Critical);//提取每个线程的信息到相应数据结构中;while(inFile){inFile >> Thread_Info[n_Thread].serial;inFile >> Thread_Info[n_Thread].entity;inFile >> Thread_Info[n_Thread].delay;char c;inFile.get(c);while(c!='\n'&& !inFile.eof()){inFile>> Thread_Info[n_Thread].thread_request[Thread_Info[n_Thread].n_request++];inFile.get(c);}n_Thread++;}//回显获得的线程信息,便于确认正确性;for(j=0;j<(int) n_Thread;j++){int Temp_serial = Thread_Info[j].serial;char Temp_entity = Thread_Info[j].entity;double Temp_delay = Thread_Info[j].delay;printf(" \n thread%2d %c %f ",Temp_serial,Temp_entity,Temp_delay);int Temp_request = Thread_Info[j].n_request;for(int k=0;k<Temp_request;k++)printf(" %d ", Thread_Info[j].thread_request[k]);cout<<endl;}printf("\n\n");//创建在模拟过程中几个必要的信号量empty_semaphore=CreateSemaphore(NULL,n_Buffer_or_Critical,n_Buffer_or_Critical,"semaphore_for_empty");h_mutex = CreateMutex(NULL,FALSE,"mutex_for_update");//下面这个循环用线程的ID号来为相应生产线程的产品读写时所//使用的同步信号量命名;for(j=0;j<(int)n_Thread;j++){std::string lp ="semaphore_for_produce_";int temp =j;while(temp){char c = (char)(temp%10);lp+=c;temp/=10;}h_Semaphore[j+1]=CreateSemaphore(NULL,0,n_Thread,lp.c_str());}//创建生产者和消费者线程;for(i =0;i< (int) n_Thread;i++){if(Thread_Info[i].entity =='P')h_Thread[i]= CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Produce),&(Thread_Info[i]),0,NULL);elseh_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consume),&(Thread_Info[i]),0,NULL);}//主程序等待各个线程的动作结束;wait_for_all = WaitForMultipleObjects(n_Thread,h_Thread,TRUE,-1);printf(" \n \nALL Producer and consumer have finished their work. \n");printf("Press any key to quit!\n");_getch();return 0;}//确认是否还有对同一产品的消费请求未执行;bool IfInOtherRequest(int req){for(int i=0;i<n_Thread;i++)for(int j=0;j<Thread_Info[i].n_request;j++)if(Thread_Info[i].thread_request[j] == req)return TRUE;return FALSE;}//找出当前可以进行产品生产的空缓冲区位置;int FindProducePosition(){int EmptyPosition;for (int i =0;i<n_Buffer_or_Critical;i++)if(Buffer_Critical[i] == -1){EmptyPosition = i;//用下面这个特殊值表示本缓冲区正处于被写状态;Buffer_Critical[i] = -2;break;}return EmptyPosition;}//找出当前所需生产者生产的产品的位置;int FindBufferPosition(int ProPos){int TempPos;for (int i =0 ;i<n_Buffer_or_Critical;i++)if(Buffer_Critical[i]==ProPos){TempPos = i;break;}return TempPos;}//生产者进程void Produce(void *p){//局部变量声明;DWORD wait_for_semaphore,wait_for_mutex,m_delay;int m_serial;//获得本线程的信息;m_serial = ((ThreadInfo*)(p))->serial;m_delay = (DWORD)(((ThreadInfo*)(p))->delay *INTE_PER_SEC);Sleep(m_delay);//开始请求生产printf("Producer %2d sends the produce require.\n",m_serial);//确认有空缓冲区可供生产,同时将空位置数empty减1;用于生产者和消费者的同步;wait_for_semaphore = WaitForSingleObject(empty_semaphore,-1);//互斥访问下一个可用于生产的空临界区,实现写写互斥;wait_for_mutex = WaitForSingleObject(h_mutex,-1);int ProducePos = FindProducePosition();ReleaseMutex(h_mutex);//生产者在获得自己的空位置并做上标记后,以下的写操作在生产者之间可以并发;//核心生产步骤中,程序将生产者的ID作为产品编号放入,方便消费者识别;printf("Producer %2d begin to produce at position %2d.\n",m_serial,ProducePos);Buffer_Critical[ProducePos] = m_serial;printf("Producer %2d finish producing :\n ",m_serial);printf(" position[ %2d ]:%3d \n" ,ProducePos,Buffer_Critical[ProducePos]);//使生产者写的缓冲区可以被多个消费者使用,实现读写同步;ReleaseSemaphore(h_Semaphore[m_serial],n_Thread,NULL);}//消费者进程void Consume(void * p){//局部变量声明;DWORD wait_for_semaphore,m_delay;int m_serial,m_requestNum; //消费者的序列号和请求的数目;int m_thread_request[MAX_THREAD_NUM];//本消费线程的请求队列;//提取本线程的信息到本地;m_serial = ((ThreadInfo*)(p))->serial;m_delay = (DWORD)(((ThreadInfo*)(p))->delay *INTE_PER_SEC);m_requestNum = ((ThreadInfo *)(p))->n_request;for (int i = 0;i<m_requestNum;i++)m_thread_request[i] = ((ThreadInfo*)(p))->thread_request[i];Sleep(m_delay);//循环进行所需产品的消费for(i =0;i<m_requestNum;i++){//请求消费下一个产品printf("Consumer %2d request to consume %2d product\n",m_serial,m_thread_request[i]);//如果对应生产者没有生产,则等待;如果生产了,允许的消费者数目-1;实现了读写同步;wait_for_semaphore=WaitForSingleObject(h_Semaphore[m_thread_request[i]],-1);//查询所需产品放到缓冲区的号int BufferPos=FindBufferPosition(m_thread_request[i]);//开始进行具体缓冲区的消费处理,读和读在该缓冲区上仍然是互斥的;//进入临界区后执行消费动作;并在完成此次请求后,通知另外的消费者本处请求已//经满足;同时如果对应的产品使用完毕,就做相应处理;并给出相应动作的界面提//示;该相应处理指将相应缓冲区清空,并增加代表空缓冲区的信号量;EnterCriticalSection(&PC_Critical[BufferPos]);printf("Consumer%2d begin to consume %2d product \n",m_serial,m_thread_request[i]);((ThreadInfo*)(p))->thread_request[i] =-1;if(!IfInOtherRequest(m_thread_request[i])){Buffer_Critical[BufferPos] = -1;//标记缓冲区为空;printf("Consumer%2d finish consuming %2d:\n ",m_serial,m_thread_request[i]);printf(" position[ %2d ]:%3d \n" ,BufferPos,Buffer_Critical[BufferPos]);ReleaseSemaphore(empty_semaphore,1,NULL);}else{printf("Consumer %2d finish consuming product %2d\n ",m_serial,m_thread_request[i]);}//离开临界区LeaveCriticalSection(&PC_Critical[BufferPos]);}}。
操作系统课程设计——生产者消费者问题

计算机与信息学院《操作系统与编译原理联合课程设计报告》专题:操作系统部分学生姓名:学号:专业班级:指导教师: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结合,将生产者-消费者问题的具体过程动态展示了出来。
生产者消费者问题操作系统课程设计

目录1 绪论 (1)1.1 实现的功能 (1)1.2 P V 操作 (1)2 生产者——消费者问题。
(2)2.1 要求 (2)2.2 生产者和消费者两个进程的程序 (2)2.3进程控制块PCB。
(3)2.4处理器的模拟。
(3)2.5程序设计 (3)3设计步骤 (4)3.1课程分析 (5)3.1.2 流程图 (5)3.1.3 测试程序 (7)3.1.4测试结果分析 (12)5 结论 (12)参考文献 (13)1 绪论生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。
模拟实现用同步机构避免发生进程执行时可能出现的与时间有关的错误。
进程是程序在一个数据集合上运行的过程,进程是并发执行的,也即系统中的多个进程轮流地占用处理器运行。
我们把若干个进程都能进行访问和修改的那些变量称为公共变量。
由于进程是并发地执行的,所以,如果对进程访问公共变量不加限制,那么就会产生“与时间有关”的错误,即进程执行后所得到的结果与访问公共变量的时间有关。
为了防止这类错误,系统必须要用同步机构来控制进程对公共变量的访问。
一般说,同步机构是由若干条原语——同步原语——所组成。
本实习要求学生模拟PV操作同步机构的实现,模拟进程的并发执行,了解进程并发执行时同步机构的作用。
1.1 实现的功能生产者-消费者问题是一个经典的进程同步问题,有m个生产者和n个消费者,它们共享可存放k件产品的缓冲区。
生产者进程生产物品,然后将物品放置在一个空缓冲区中,供消费者进程消费。
消费者进程从缓冲区中获得物品,然后释放缓冲区。
当生产者进程生产物品时,如果没有空缓冲区可用,那么生产者进程必须等待消费者线程释放出一个空缓冲区。
当消费者进程消费物品时,如果没有满的缓冲区,那么消费者进程将被阻塞,直到新的物品被生产出来。
1.2 P V 操作(1) PV操作同步机构,由P操作原语和V操作原语组成,它们的定义如下:P操作原语P (s):将信号量s减去1,若结果小于0,则执行原语的进程被置成等待信号量s的状态。
操作系统课程设计生产者消费者

生产者消费者问题 (Producer-consumer problem) , 也称有限缓冲问题 (Bounded-buffer problem),是一个多线程同步问题的经典案例。 该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”— —在实际运行时会发生的问题。 生产者的主要作用是生成一定量的数据放到缓冲区中, 然后 重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者 不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。 要解决该问题,就必须让生产者在缓冲区满时休眠(或者放弃数据),等到下次消费者 消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让 消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采 用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容 易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能 被推广到多个生产者和消费者的情形。
5
pthread_mutex_lock(&lock); while (q->num == 0) { pthread_cond_wait(&empty, &lock); } sem_wait(&product_number); q->front = (q->front + 1) % NUM; char c = q->productc[q->front]; q->productc[q->front] = ' '; q->num--; printf("消费者 1 显示内容: %c\n", c); printf("产品数量:%d\n", q->num); sem_post(&blank_number); if (q->num == NUM - 1) { pthread_cond_signal(&full); } pthread_mutex_unlock(&lock); sleep(rand() % 2); } } void *consumer2(void *arg) { struct P_Queue *q; q = (struct P_Queue *) arg; while (1) { pthread_mutex_lock(&lock); while (q->num == 0) { pthread_cond_wait(&empty, &lock); } sem_wait(&product_number); q->front = (q->front + 1) % NUM; char c = q->productc[q->front]; char d = 0; if(c>=65 && c<=90) { d = c+32;} else { d = c-32;} q->productc[q->front] = ' '; q->num--; printf("消费者 2 更改大小写:%c---%c\n", c,d); printf("产品数量:%d\n", q->num); sem_post(&blank_number); if (q->num == NUM - 1) { pthread_cond_signal(&full); }
生产者消费者问题操作系统课程设计

目录1 绪论 (3)1.1 实现的功能 (3)1.2 P V 操作 (3)2 生产者——消费者问题。
(4)2.1 要求 (4)2.2 生产者和消费者两个进程的程序 (4)2.3进程控制块PCB。
(5)2.4处理器的模拟。
(5)2.5程序设计 (6)3设计步骤 (7)3.1课程分析 (7)3.1.2 流程图 (7)3.1.3 测试程序 (9)3.1.4测试结果分析 (14)5 结论 (15)参考文献 (16)1 绪论生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。
模拟实现用同步机构避免发生进程执行时可能出现的与时间有关的错误。
进程是程序在一个数据集合上运行的过程,进程是并发执行的,也即系统中的多个进程轮流地占用处理器运行。
我们把若干个进程都能进行访问和修改的那些变量称为公共变量。
由于进程是并发地执行的,所以,如果对进程访问公共变量不加限制,那么就会产生“与时间有关”的错误,即进程执行后所得到的结果与访问公共变量的时间有关。
为了防止这类错误,系统必须要用同步机构来控制进程对公共变量的访问。
一般说,同步机构是由若干条原语——同步原语——所组成。
本实习要求学生模拟PV操作同步机构的实现,模拟进程的并发执行,了解进程并发执行时同步机构的作用。
1.1 实现的功能生产者-消费者问题是一个经典的进程同步问题,有m个生产者和n个消费者,它们共享可存放k件产品的缓冲区。
生产者进程生产物品,然后将物品放置在一个空缓冲区中,供消费者进程消费。
消费者进程从缓冲区中获得物品,然后释放缓冲区。
当生产者进程生产物品时,如果没有空缓冲区可用,那么生产者进程必须等待消费者线程释放出一个空缓冲区。
当消费者进程消费物品时,如果没有满的缓冲区,那么消费者进程将被阻塞,直到新的物品被生产出来。
1.2 P V 操作(1) PV操作同步机构,由P操作原语和V操作原语组成,它们的定义如下:P操作原语P (s):将信号量s减去1,若结果小于0,则执行原语的进程被置成等待信号量s的状态。
操作系统课程设计“生产者-消费者”问题
《操作系统》课程设计题目:“生产者-消费者”问题学院:信息工程学院专业:计算机科学与技术班级:计科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号生产者线程的产品。
现代操作系统课程设计报告 生产者与消费问题
进程同步模拟设计——生产者和消费者问题第一章课设任务本课程设计的任务在于,通过编写一个具体的有关操作系统进程同步互斥的经典问题,加强对操作系统实现进程间同步与互斥的机制的理解。
同时培养提出问题、发现知识、使用工具、解决问题的能力。
具体地,我们要编制出一个程序,利用PV原语以及进程创建、同步、互斥、销毁等相关的系统调用来模拟“生产者—消费者”问题。
第二章背景介绍2.1 “生产者—消费者”问题(the producer-consumer problem)生产者-消费者(producer-consumer)问题,也称作有界缓冲区(bounded-buffer)问题,两个进程共享一个公共的固定大小的缓冲区。
其中一个是生产者,用于将消息放入缓冲区;另外一个是消费者,用于从缓冲区中取出消息。
问题出现在当缓冲区已经满了,而此时生产者还想向其中放入一个新的数据项的情形,其解决方法是让生产者此时进行休眠,等待消费者从缓冲区中取走了一个或者多个数据后再去唤醒它。
同样地,当缓冲区已经空了,而消费者还想去取消息,此时也可以让消费者进行休眠,等待生产者放入一个或者多个数据时再唤醒它。
问题分析:该问题涉及到操作系统进程管理当中的两个重要概念——同步和互斥。
同步,表现在生产者和消费者需要协同工作,步调不能拉开太大(由缓冲区大小n决定,n越大,缓冲空间越大,步调可以拉得越开;n=1时,必须是生产一个,消费一个,生产者和消费者就完全同步了)。
当步调差距超过极限时,走在前面的当前进程(生产者)调用P 原语时由于资源耗尽,被阻塞;步调靠后的继续向前推进。
由此实现同步。
互斥,表现在生产者与消费者、生产者与生产者、消费者与消费者任何两个成员之间必须互斥地使用缓冲区。
当有一个成员进入缓冲区存/取产品时,其他成员将被关在门外排队等候(被阻塞);当完毕时,通知队首成员进入。
由操作系统理论可知,我们需要三个信号量,分别命名full, empty, mutex,来分别代表消费者的可用资源数、生产者的可用资源数、缓冲区是否可用。
操作系统课程设计生产者-消费者问题附代码
枣庄学院信息科学与工程学院课程设计任务书题目:生产者-消费者问题的实现姓名:学号:专业:计算机科学与技术课程:操作系统指导教师:刘彩霞职称:讲师完成时间:2012年5月----2012 年6月枣庄学院信息科学与工程学院制课程设计任务书及成绩评定目录第1章引言 (1)1.1 设计背景 (1)1.2 问题分类 (1)1.3 解决方案 (1)第2章设计思路及原理 (2)第3章程序详细设计 (3)3.1程序模块设计 (3)3.2程序代码结构 (5)第4章实验结果 (7)第5章实验总结 (8)附录:实验代码 (9)第1章引言1.1 设计背景生产者-消费者问题是一个经典的进程同步问题,该问题最早由Dijkstra 提出,用以演示他提出的信号量机制。
在同一个进程地址空间内执行的两个线程。
生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。
消费者线程从缓冲区中获得物品,然后释放缓冲区。
当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。
当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
1.2 问题分类根据缓冲区的个数、大小以及生产者消费者的个数可以分为以下几类:1.单缓冲区(适合单或多生产消费者);2.环行多缓冲区(或无穷缓冲区)单生产消费者;3.环行多缓冲区多生产消费者;1.3 解决方案1.用进程通信(信箱通信)的方法解决;2.进程消息缓冲通信;3.进程信箱通信;第2章设计思路及原理设计了两个主要函数:生产者函数、消费者函数;设计了三个信号量:full信号量,判断缓冲区是否有值,初值为0;empty信号量,判断缓冲区是否有空缓冲区,初值为缓冲区数;mutex信号量作为互斥信号量,用于互斥的访问缓冲区。
生产者函数通过执行P操作信号量empty减1,判断缓冲区是否有空。
有空则互斥的访问缓冲区并放入数据,然后释放缓冲区,执行V操作,信号量full 加1。
计算机操作系统课程设计报告《生产者---消费者问题》
计算机操作系统课程设计报告《生产者---消费者问题》《计算机操作系统》课程设计题目:生产者---消费者问题专业:软件工程年级:2010级小组成员: A B指导教师:时间:地点:2012年5 月摘要生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。
该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。
生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。
与此同时,消费者也在缓冲区消耗这些数据。
该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。
生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
目录1. 概述 (4)2. 课程设计任务及要求 (4)2.1 设计任务 (4)2.2 设计要求 (4)2.3 分工日程表 (4)3. 算法及数据结构 (5)3.1算法的总体思想 (5)3.2 生产者模块 (5)3.3 消费者模块 (7)4. 程序设计与实现 (8)4.1 程序流程图 (8)4.2 程序代码 (9)4.3 实验结果 (14)5. 结论 (17)6. 收获、体会和建议 (17)6.1收获......................................... 错误!未定义书签。
7. 参考文献 (18)1. 概述本课题设计是完成了“操作系统原理”课程进行的一次全面的综合训练,通过这次课程设计,充分检验学生对课程的掌握程度和熟练情况,让学生更好的掌握操作系统的原理及其实现方法,加深对课程的基础理论和算法的理解,加强学生的动手能力。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(操作系统课程设计)生产者和消费者学生姓名:学生学号:班级:0311401、02、03、04班制二〇一三年十二月一、课程题目分析这个题目是生产者向消费者提供商品,消费者消耗商品,并且两组人共用同一缓冲区。
生产者提供了商品之后消费者才能去取商品,消费者若不取走商品则当缓冲区用完之后生产者则不能再向缓冲区中添加新的商品。
思考问题:(1)对于生产者进程:每产生一个数据,则需去访问共用缓冲区是否有已满,未满则可以将该数据存入并通知消费者进程,否则不能。
(2)对于消费者进程:每当想去消费(取出数据)时,则需访问缓冲区是否为空,为空则不能消费(取出数据),否则可以取,并通知生产者。
(3)缓冲区是个临界资源,所有的进程对于该空间都是共享的,所以,还有互斥问题存在。
二、课程设计目的通过实验模拟生产者与消费者之间的关系,了解并掌握他们之间的关系及原理。
由此增加对进程同步问题的了解:(1)掌握基本的同步互斥算法,理解生产者与消费者模型(2)了解windows中多线程(多进程)的并发执行机制,线程(进程)间的同步于互斥(3)学习使用windows中基本的同步对象,掌握相应的API。
三、课程设计内容有n个生产者和m个消费者,连接在具有k个单位缓冲区的有界环转缓冲上,故又称有界缓冲问题。
其中P i和C j都是并发进程,只要缓冲区未满,生产者进程P i所生产的产品就可投入缓冲区;类似地,只要缓冲区非空,消费者进程C j就可以从缓冲区取走并消耗产品。
四、开发环境操作系统:Windows系统编写语言:C++语言五、系统分析设计(一)算法原理生产者——消费者问题是典型的进程同步问题,这些进程必须按照一定的生产率和消费率来访问共享缓冲区,用P、V操作解决生产者和消费者共享单缓冲区的问题,可设置两个信号量empty和full,其初值分别为1和0,empty 指示能否向缓冲区放入产品,full指示能否从缓冲区取出产品。
为了使其协调工作,必须使用一个信号量mutex(初值为1),以限制生产者和消费者互斥地对缓冲区进行存取,另用两个信号量empty1(初值为缓冲区大小)和full1(初值为0),以保证生产者不向已满的缓冲区中放入产品,消费者不从空缓冲区中取产品。
(二)功能描述生产者功能描述:在同一个进程地址空间内执行两个线程。
生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。
当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。
消费者功能描述:消费者线程从缓冲区获得物品,然后释放缓冲区,当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
(三)算法流程图生产者流程图:消费者流程图:总的流程图:(四)数据结构及部分函数描述(1)类SeqSquare:对类SeqSquare的声明及其中一些函数class SeqSquare{public:SeqSquare(int n);~SeqSquare();void P(int x); //p操作void V(int x); //v操作bool IsEmpty(); //判断是否为空bool IsFull(); //判断是否已满void deca();void decb();int getSize();int getmaxSize();int gettop();int geta();int getb();protected:private:int *elements;int top,a,b,maxSize;};说明:①用动态整型数组*elements来代表缓冲区,不管是生产产品还是对已有产品的消费都需要访问该缓冲区。
②函数IsFull()用于判断缓冲区是否已满,生产者能否使用缓冲区。
③函数IsEmpty()用于判断缓冲区是否为空,消费者能否使用缓冲区。
(2)生产者和消费者操作及显示函数showbuf:void producer(SeqSquare *a) //生产者操作{a->P(1);}void consumer(SeqSquare *a) //消费者操作{a->V(1);}//缓冲区显示void showbuf(SeqSquare *a){int i=a->getSize();}(3)在实现本程序的生产者消费者模型时,具体地通过以下同步对象实现互斥:①设一个互斥量Mutex,以实现生产者在查询和保留缓冲区的下一个空位置时进行互斥。
②每一个生产者用一个信号量与消费者同步,通过设置Full实现,该组信号量用于表示相应产品以生产。
同时用一个表示空缓冲区数目的信号量Empty 进行类似的同步,指示缓冲区中是否存在空位置,以便开始生产下一个产品。
(四)调试过程为解决生产者、消费者问题,应该设置两个资源信号量,其中一个表示空缓冲区的数目,用Full表示,其初值为用户输入的缓冲区的大小,另一个表示缓冲区中产品的数目,用Empty表示,其初值为0.另外,由于缓冲区是一个临界资源,必须互斥使用,所以还需要再设置一个互斥信号量Mutex,其初值为1.在生产者、消费者问题中,信号量实现两种功能。
首先,他是生产产品和消费产品的计数器,计数器的初值是可使用的资源数目(缓冲区的长度)。
其次,他是确保产品的生产者和消费者之间的动作同步的同步器。
生产者要生产一个产品时,首先对资源信号量Full和互斥信号量Mutex进行P操作,申请资源。
如果可以通过的话,就生产一个产品,并把产品送人缓冲区。
然后对互斥信号量Mutex和资源信号量Empty进行V操作,释放资源。
消费者要消费一个产品时,首先对资源信号量Empty和互斥信号量Mutex 进行P操作,申请资源。
如果可以通过的话就从缓冲区取出一个产品并消费掉。
然后对互斥信号量Mutex和资源信号量Full进行V操作,释放资源。
如果缓冲区中已经没有可用资源,就把申请资源的进程添加到等待队列的队尾。
如果有一个资源被释放,在等待队列中的第一个进程被唤醒并取得这个资源的使用权。
(五)参考资料《操作系统教程》孙钟秀高等教育出版社《C++程序设计》谭浩强高等教育出版社六、运行实例及结果分析(一)运行实例缓冲区大小为3,先生产一件产品,显示缓冲区,再接着生产一件产品,消耗一件产品,显示缓冲区,在消耗两件产品,再生产4件产品,改变缓冲区的大小为6,显示缓冲区,选择一个未出现的选项,退出程序。
(二)结果显示(三)结果分析(1)在每个程序中需要先做P,后做V,二者要成对出现,夹在二者中间的代码段就是该进程的临界区。
(2)对同步信号量full和empty的P,V操作同样必须成对出现,但它们分别位于不同的程序中。
(3)无论在生产者进程中还是消费者进程中,两个P操作的次序不能颠倒:应先执行同步信号量的P操作,然后执行互斥信号量的P操作。
否则可能造成进程死锁。
七、个人体验虽然我也很想用java语言写这个程序,但是由于自己学艺不精,所以只能用C++写。
通过这个实验我发现我以前有很多知识都忘记了,重新拿起课本学习时发现原来很多不懂得问题都有了新的认识,有一种豁然开朗的感觉。
也为我考研开了一个好的开头。
我认为我完成的这个设计做的比较出色的地方是对C++语言中类以及数组的运用,其实这里我对数组的操作是按照“先进先出”的方法进行运作的,这是参考了栈的工作原理,因为缓冲区一般也是堆栈,比较符合设计要求。
这次实验中我感觉做的很粗糙,自己所想的模拟过程的确得到实现了,但是感觉灵活性不太高,思考还不过全面,应该以后多注意一下,多考虑考虑才是。
在这次实验中我重新将《C++程序设计》和《数据结构》的几个重要章节复习了一遍,对类、数组、C++的I/O流类库以及堆栈的语句格式、注意细节都再一次熟悉,感觉蛮有趣的。
不过,在编程过程中许多语句的小问题还真是出现不少,而且感觉自己对C++强大丰富的语句方法用得太呆板,不够灵活,总是想到那些常用的,而忽略了颗粒让语句更简短的方法,以后要多多注意才是。
八、附录// 生产者消费者1.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include "iostream"using namespace std;class SeqSquare{public:SeqSquare(int n);~SeqSquare();void P(int x); //p操作void V(int x); //v操作bool IsEmpty(); //判断是否为空bool IsFull(); //判断是否已满void deca();void decb();int getSize();int getmaxSize();int gettop();int geta();int getb();protected:private:int *elements;int top,a,b,maxSize;};bool SeqSquare::IsEmpty() //判断是否为{return(top==-1)?true:false;}bool SeqSquare::IsFull() //判断是否已满{return(top>=maxSize-1)?true:false;}void SeqSquare::deca(){a--;}void SeqSquare::decb(){b--;}int SeqSquare::getSize(){return top+1;int SeqSquare::getmaxSize() {return maxSize;}int SeqSquare::gettop(){return top;}int SeqSquare::geta(){return a;}int SeqSquare::getb(){return b;}SeqSquare::SeqSquare(int n) {top =-1;a =b =0;maxSize = n;elements = new int[maxSize]; }void SeqSquare::P(int x){if(IsFull()==true){a=a+1;}else{elements[++top] = x;}}void SeqSquare::V(int x){if(IsEmpty()==true){b = b+1;}else{x = elements[top--];}}void producer(SeqSquare *a) //生产者操作{a->P(1);}void consumer(SeqSquare *a) //消费者操作{a->V(1);}SeqSquare::~SeqSquare(){delete elements;}//缓冲区显示void showbuf(SeqSquare *a){int i=a->getSize();}int main(){int i,n;cout<<"请输入缓冲区大小:"<<endl;cin>>n;SeqSquare *s;s = new SeqSquare(n);while(i!=4){cout<<"请选择操作:"<<endl;cout<<"1.生产一件产品;2.消费一件产品"<<endl;cout<<"3.显示缓冲区; 4.退出系统。