操作系统课程设计生产者-消费者问题附代码
操作系统课程设计——生产者消费者问题
计算机与信息学院《操作系统与编译原理联合课程设计报告》专题:操作系统部分学生姓名:学号:专业班级:指导教师: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结合,将生产者-消费者问题的具体过程动态展示了出来。
计算机操作系统课程设计源代码《生产者---消费者问题源代码》
《生产者---消费者问题源代码》#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_P5/*定义数据为生产者*/#define NUM_THREADS_C5/*定义数据为消费者*/#define MAX_BUFFER20/*定义数据为缓存区*/#define RUN_TIME20/*定义运行时间*/int buffer[MAX_BUFFER];/*定义最大缓存区*/int produce_pointer=0,consume_pointer=0;/*定义指针*/sem_t producer_semaphore,consumer_semaphore,buffer_mutex;/*定义信号量,互斥*/pthread_t threads_p[NUM_THREADS_P];/*声明生产者线程*/pthread_t threads_c[NUM_THREADS_C];/*声明消费者线程*/FILE*fd;void*producer_thread(void*tid);/*声明生产者线程*/void*consumer_thread(void*tid);/*声明消费者线程*/void showbuf();/*声明showbuf方法*/void handler(){int i;/*定义i*/for(i=0;i<NUM_THREADS_P;i++)pthread_cancel(threads_p[i]);/*for循环,如果i<NUM_THREADS_P,则pthread_cancel(threads_p[i]);并且i++*/ for(i=0;i<NUM_THREADS_C;i++)pthread_cancel(threads_c[i]);/*for循环,如果i<NUM_THREADS_C,则pthread_cancel(threads_c[i]);并且i++*/}int main(){int i;/*定义i*/signal(SIGALRM,handler);/*定义信号量*/fd=fopen("output.txt","w");/*打开一个文件用来保存结果*/sem_init(&producer_semaphore,0,MAX_BUFFER);/*放一个值给信号灯*/sem_init(&consumer_semaphore,0,0);sem_init(&buffer_mutex,0,1);for(i=0;i<MAX_BUFFER;i++)buffer[i]=0;/*引发缓冲*//*创建线程*/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);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);/*等待线程退出*/sem_destroy(&producer_semaphore);/*清除信号灯*/sem_destroy(&consumer_semaphore);/*清除信号灯*/sem_destroy(&buffer_mutex);/*清除缓存区*/fclose(fd);/*关闭文件*/return0;}void*producer_thread(void*tid){pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);/*设置状态,PTHREAD_CANCEL_ENABLE是正常处理cancel信号*/ while(1){sem_wait(&producer_semaphore);/*等待,需要生存*/srand((int)time(NULL)*(int)tid);sleep(rand()%2+1);/*一个或两个需要生产*/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){printf("生产者:%d指针指向:%2d生产产品号:%2d\n",(int)tid,19,buffer[19]);/*输出生产者,指针,缓存区*/fprintf(fd,"生产者:%d指针指向:%2d生产产品号:%2d\n",(int)tid,19,buffer[19]);/*输出生产者,指针,缓存区*/}else{printf("生产者:%d指针指向:%2d生产产品号:%2d\n",(int)tid,produce_pointer-1,buffer[produce_pointer-1]);/*输出生产者,指针,缓存区*/fprintf(fd,"生产者:%d指针指向:%2d生产产品号:%2d\n",(int)tid,produce_pointer-1,buffer[produce_pointer-1]);/*输出生产者,指针,缓存区*/}showbuf();sem_post(&buffer_mutex);sem_post(&consumer_semaphore);/*通知消费者缓冲区不是空的*/srand((int)time(NULL)*(int)tid);sleep(rand()%5+1);/*等待几秒钟,然后继续生产*/}return((void*)0);}void*consumer_thread(void*tid){/*可以被其他线程使用*/pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);/*设置状态,PTHREAD_CANCEL_ENABLE是忽略cancel信号*/while(1){sem_wait(&consumer_semaphore);/*通知消费者消费*/srand((int)time(NULL)*(int)tid);sleep(rand()%2+1);/*一个或两个来消费*/sem_wait(&buffer_mutex);printf("消费者:%d指针指向:%2d消费产品号:%2d\n",(int)tid,consume_pointer,buffer[consume_pointer]);/*输出消费者,消费者指针,缓存区*/fprintf(fd,"消费者:%d指针指向:%2d消费产品号:%2d\n",(int)tid,consume_pointer,buffer[consume_pointer]);/*输出消费者,消费者指针,缓存区*/buffer[consume_pointer]=0;/*消费者指针指向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);/*等待几秒钟,然后继续消费*/}return((void*)0);}/*查看缓冲区内容*/void showbuf(){int i;/*定义i*/printf("buffer:");/*输出缓存区*/fprintf(fd,"buffer:");/*输出缓存区*/for(i=0;i<MAX_BUFFER;i++){printf("%2d",buffer[i]);/*输出缓存区i*/fprintf(fd,"%2d",buffer[i]);/*输出缓存区i*/ }printf("\n\n");/*换行*/fprintf(fd,"\n\n");/*换行*/}。
操作系统生产者消费者问题代码
#include <windows.h>#include <fstream.h>#include <iostream.h>#include <string>#include <conio.h>//声明所需变量int in=0;int out=0;HANDLE h_Thread[20]; //线程数组HANDLE empty_Semaphore; //表示空缓冲区的信号量HANDLE full_Semaphore; //表示空缓冲区的信号量HANDLE mutex;struct data{int ID;//序号char type;//类型,是生产者还是消费者,p or cdouble delay;//线程延迟的时间,对应生产者生产产品的时间或消费者消费产品的时间};data ThreadInfo[20]; //线程信息数组int length; //线程信息数组中实际的线程个数void Produce(void *p);//生产者进程void Consume(void *p);//消费者进程void input(void);int main(void){input();//初始化临界区对象//InitializeCriticalSection(&PC_Critical);empty_Semaphore=CreateSemaphore(NULL,10,10,NULL);full_Semaphore=CreateSemaphore(NULL,0,10,NULL);mutex = ::CreateMutex(NULL,FALSE,NULL);cout<<"下面生产者和消费者开始工作!!"<<endl;cout<<endl;//创建生产者和消费者线程for(int i=0;i<length;i++){if(ThreadInfo[i].type=='p')h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Produce),&(ThreadInfo[i]), 0,NULL);elseh_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consume),&(ThreadInfo[i]),0,N ULL);}//主程序等待各个线程的动作结束WaitForMultipleObjects(length,h_Thread,TRUE,-1);cout<<endl;::Sleep(1000000);cout<<"所有的生产者和消费者都完成了它们的工作!!"<<endl<<endl;return 0;}//***************************************************************************** ************//生产者进程//***************************************************************************** *************void Produce(void *p){}//***************************************************************************** ************//消费者进程//***************************************************************************** *************void Consume(void *p){//局部变量声明int my_id;double my_delay;//从线程信息数组中获得信息my_id =((data*)(p))->ID;my_delay=((data*)(p))->delay;//开始请求xiaofeicout<<"消费者"<<my_id<<"发出消费请求。
操作系统课程设计“生产者-消费者”问题
《操作系统》课程设计题目:“生产者-消费者”问题学院:信息工程学院专业:计算机科学与技术班级:计科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号生产者线程的产品。
操作系统实验生产者与消费者问题代码
操作系统实验生产者与消费者问题代码#include "stdafx.h"#include "windows.h"#include "fstream.h"#include "string"#include "conio.h"#define MAX_BUFFER_NUM 10#define INTE_PER_SEC 1000#define MAX_THREAD_NUM 64struct ThreadInfo{int serial;char entity;double delay;int thread_request[MAX_THREAD_NUM];int n_request;};CRITICAL_SECTION PC_Critical[MAX_BUFFER_NUM]; int Buffer_Critical[MAX_BUFFER_NUM];ThreadInforThread_Info[MAX_BUFFER_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 FindProducePosition();int FindBufferPosition(int);int main(void){DWORD wait_for_all;ifstream inFile;for (int i=0;i<max_buffer_num;i++)< p="">Buffer_Critical[i] = -1;for (int j=0;j<max_thread_num;j++)< p="">for (int k=0;k<max_thread_num;k++)< p=""> Thread?_Info[j].thread_request[k] = -1;Thread_Info[j].n_request = 0;}for (i=0;i<="" p="">inFile.open("test.txt")inFile>>n_Buffer_or_Critial;inFile.get();printf("输入文件是:\n")'printf ("%d\n",(int )n_Buffer_or_Critial);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",T emp_serial,Temp_entity,T emp_delay);int Temp_request = Thread_Info[j].n_request;for (int k=0;k<temp_request;k++)< p="">printf("%d ",Thread_Info[j].thread_request[k]);cout<<end1;< p="">}printf("\n\n");empty_semaphore=CreateSemaphore(NULL,n_Buffer_or_Cri tical,n_Buffer_or_Critical,"semaphor e_for_empty");h_mutex = CreateMutex(NULL,FALSE,"mutex_for_update");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_ROUT INE))(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++)< p="">for (int j=0;j<thread_info[i].n_request;j++)< p="">if(Thread_Info[i].thread_request[j] == req)return TRUE;}int FindProducePosition(){int EmptyPosition;for(int i=0;i<n_buffer_or_critical;i++)< p="">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++)< p="">Temppos = i;break;}return Temppos;}void produce(void*){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);wait_for_semaphore=WaitForSingleObject(enpty_semaphore,-1);wait_for_mutex = WaitForSingleObject(h_mutex,-1);int producepos = FindProducePosition();ReleaseMutex(h_mutex);prientf("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_Clitical [produce-pos]);ReleaseSemaphore(h_Semaphore[m_serial],n_Thread,NULL);}void Consum(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;ithread_request[i]);sleep(m_delay);for(i=0;i<m_requestnum;i++){< p="">printf("Consumer %2d request to consume %2d product\n",m_serial,m_thread_request[i]);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 consum %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]);rtintf(" position [%2d]:%3d.\n",Bufferpos,Buffer_Critical[Buffer-pos]);ReleaseSemaphore(empty_semaphore,1,NULL);}else{printf ("Consumer %2d finish consuming product %2d\n",m_serial,m_thread_request[i]);}LeaveCriticalSection(&PC_Critical[Bufferpos]);}}</m_requestnum;i++){<></n_buffer_or_critical;i++)<></n_buffer_or_critical;i++)<></thread_info[i].n_request;j++)<></n_thread;i++)<></end1;<></temp_request;k++)<></max_thread_num;k++)<></max_thread_num;j++)<></max_buffer_num;i++)<>。
C语言编程模拟生产者和消费者问题(附代码程序)
实验三编程模拟生产者和消费者问题一、实验目的和要求模拟实现用同步机构避免发生进程执行时可能出现的与时间有关的错误。
进程是程序在一个数据集合上运行的过程,进程是并发执行的,也即系统中的多个进程轮流地占用处理器运行。
我们把若干个进程都能进行访问和修改的那些变量称为公共变量。
由于进程是并发地执行的,所以,如果对进程访问公共变量不加限制,那么就会产生“与时间有关”的错误,即进程执行后所得到的结果与访问公共变量的时间有关。
为了防止这类错误,系统必须要用同步机构来控制进程对公共变量的访问。
一般说,同步机构是由若干条原语——同步原语——所组成。
本实习要求学生模拟PV操作同步机构的实现,模拟进程的并发执行,了解进程并发执行时同步机构的作用。
二、实验环境Windows操作系统和Visual C++6.0专业版或企业版三、实验步骤模拟PV操作同步机构,且用PV操作解决生产者——消费者问题。
[提示]:(1) PV操作同步机构,由P操作原语和V操作原语组成,它们的定义如下:P操作原语P (s):将信号量s减去1,若结果小于0,则执行原语的进程被置成等待信号量s的状态。
V操作原语V (s):将信号量s加1,若结果不大于0,则释放一个等待信号量s的进程。
这两条原语是如下的两个过程:procedure p (var s: semaphore);begin s: = s-1;if s<0 then W (s)end {p}procedure v (var s: semaphore);egin s: = s+1;if s 0 then R (s)end {v}其中W(s)表示将调用过程的进程置为等待信号量s的状态;R(s)表示释放一个等待信号量s的进程。
在系统初始化时应把semaphore定义为某个类型,为简单起见,在模拟实习中可把上述的semaphore直接改成integer。
(2) 生产者——消费者问题。
假定有一个生产者和一个消费者,生产者每次生产一件产品,并把生产的产品存入共享缓冲器以供消费者取走使用。
操作系统课程设计生产者-消费者问题附代码
枣庄学院信息科学与工程学院课程设计任务书题目:生产者-消费者问题的实现姓名:学号:专业:计算机科学与技术课程:操作系统指导教师:刘彩霞职称:讲师完成时间: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. 概述本课题设计是完成了“操作系统原理”课程进行的一次全面的综合训练,通过这次课程设计,充分检验学生对课程的掌握程度和熟练情况,让学生更好的掌握操作系统的原理及其实现方法,加深对课程的基础理论和算法的理解,加强学生的动手能力。
操作系统之生产者消费者问题(c++实现)
操作系统之生产者消费者问题(c++实现)操作系统课程设计报告专业计算机科学与技术丁可b计123班1210704314李先锋2021年11月20日学生姓名班学级号指导教师顺利完成日期信息工程学院题目:生产者-消费者问题的演示同时实现一、设计目的本课程设计就是自学回去“操作系统原理”课程后展开的一次全面的综合训练,通过课程设计,更好地掌控操作系统的原理及同时实现方法,增进对操作系统基础理论和关键算法的认知,强化学生的动手能力。
二、设计内容1、详述用进程同步方法解决“生产者-消费者”问题,c或c++语言实现。
1、设计目的通过研究进程mammalian和信号量机制,同时实现生产者-消费者问题的mammalian掌控。
2、设计建议1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容,当前指针位置和生产者/消费者进程的标识符。
表明:存有界缓冲区(提示信息:存有界缓冲区需用数组同时实现)内建有20个存储单元,放进/抽出的数据项预设为1-20这20个整型数。
2)生产者和消费者各有两个以上。
3)多个生产者或多个消费者之间须存有共享资源对缓冲区展开操作方式的函数代码。
2、设计原理在同一个进程地址空间内执行的两个线程生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。
消费者线程从缓冲区中获得物品,然后释放缓冲区。
当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。
当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
3、详细设计及编码定义两个信号量handleg_hfullsemaphore;//资源信号量:缓冲区八十handleg_hemptysemaphore;//资源信号量:缓冲区空unsignedshortin=0;//用于记录生产者的指针位置unsignedshortout=0;//用于记录消费者的指针位置handleg_hmutex;//线程间的互斥信号量生产者进程while(true){生产一个产品;p(g_hemptysemaphore);p(mutex1);产品送往buffer(in);in=(in+1)modn;v(mutex1);v(g_hfullsemaphore);}消费者进程while(true){p(g_hfullsemaphore);p(mutex2);从buffer(out)中抽出产品;out=(out+1)modn;v(mutex2);v(g_hemptysemaphore);(算法流程图、编程及程序注解等)主要的方法:4、运行结果分析1、运行示例在c++中运转源程序,程序主界面图片.按contrary及提出申请资源和缓冲区展开p操作方式和提出申请不相容(生产者和消费者都就是2个)(运行界面截图、界面说明、输入输出数据说明和分析等)附录代码:#include#includeconstunsignedshortsize_of_buffer=20;//有界缓冲区长度intg_buffer[size_of_buffer];//开拓缓冲区?用数组则表示?可以看作就是一个循环队列unsignedshortproductid=0;//崭新生产出的产品的产品号unsignedshortconsumeid=0;//被消耗的产品的产品号unsignedshortin=0;//产品进缓冲区时的缓冲区下标?用于记录生产者的指针位置unsignedshortout=0;//产品出缓冲区时的缓冲区下标?用于记录消费者的指针位置boolg_continue=1;//控制程序运行:1表示继续运行?0表示停止运行handleg_hmutex;//线程间的互斥信号量handleg_hfullsemaphore;//资源信号量:缓冲区八十handleg_hemptysemaphore;//资源信号量:缓冲区空dwordwinapiproducer(lpvoid);//生产者线程dwordwinapiconsumer(lpvoid);//消费者线程constunsignedshortproducers_count=2;//生产者的个数constunsignedshortconsumers_count=2;//消费者的个数constunsignedshortthreads_count=producers_count+consumers_count;//总线程数。
(完整版)者消费者问题 操作系统毕业课程设计java源代码
************************************** Main主函数**************************************************** package JM;import java.awt.BorderLayout;import java.awt.CardLayout;import java.awt.Color;import java.awt.Container;import java.awt.Dimension;import java.awt.FlowLayout;import java.awt.GridLayout;import java.awt.Toolkit;import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.util.Date;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JOptionPane; import javax.swing.JPanel;import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JSlider;import javax.swing.JTextArea;import javax.swing.JTextField;import javax.swing.event.ChangeEvent;import javax.swing.event.ChangeListener;import Class.Buffer;import Class.Consumer;import Class.Count;import Class.InterfaceModule;import Class.Producer;import Class.Semaphore;import java.awt.*;import javax.swing.*;import java.awt.event.*;import javax.swing.event.*;import java.util.*;public class Main extends JFrame{public Main frame;定义引用自身的主界面对象,在其他类中引用,以建立类间的联系int p,c,b;生产者数,消费数,缓冲区大小JPanel p0;JPanel p1;JPanel p2;JPanel p21;JPanel p211,p212,p213;JPanel p22;JPanel p3;JPanel p31;JPanel p4;JPanel p41;JScrollPane p41;JPanel p42;JPanel p43;JPanel p44;JLabel lb1;JLabel lb2;JLabel lb3;JLabel lb4;JLabel lb5;JLabel lb6;JLabel lb7;public JTextArea a1;JButton b1;JButton b2;JButton b3;JButton b4;JButton b5;public JProgressBar pb1;生产者生产速度进度条public JProgressBar pb2;消费者消费速度进度条public JProgressBar pb3;缓冲区剩余产品数进度条public JSlider js1;设置生产速度滑动竿public JSlider js2;设置消费熟读滑动杆public JSlider js3;信号量******************************* *********************************************************Semaphore notfull,notempty;不满和不空信号量Count notfull_count,notempty_count;InterfaceModule IM;Buffer buffer;=new Buffer(b,0);******************************************** 采用管程之后,此处的初始化应去掉Semaphore mutex;=new Semaphore(1);互斥信号量Semaphore full;=new Semaphore(0);同步信号量Semaphore empty;=new Semaphore(b);同步信号量*public Thread[] thread; =new Thread[100];线程组Thread[] thread1 =new Thread[100];public Main(String name,int pp,int cc,int bb) {TODO Auto-generated constructor stubsuper(name);this.p=pp;由界面传入的生产者消费者以及缓冲区的数量this.c=cc;this.b=bb;js1=new JSlider(0,10);js2=new JSlider(0,10);pb1=new JProgressBar(JProgressBar.VERTICAL,0,10);进度条pb2=new JProgressBar(JProgressBar.VERTICAL,0,10);进度条pb3=new JProgressBar(JProgressBar.VERTICAL,0,b);进度条pb1.setOrientation(JProgressBar.VERTICAL);pb1.setStringPainted(true);pb2.setStringPainted(true);pb3.setStringPainted(true);buffer=new Buffer(this.b,0);* 采用管程之后,此处应去掉mutex=new Semaphore(1); 互斥信号量full=new Semaphore(0);empty=new Semaphore(this.b);*frame=this;buffer=new Buffer(b,0);notfull=new Semaphore(0,frame);IM=new InterfaceModule(frame);notempty=new Semaphore(0,frame);notfull_count=new Count(0);notempty_count=new Count(0);thread=new Thread[100];thread=new Thread[100];aa=this;******************************************************** a1=new JTextArea(12,50);p0=new JPanel();主面板p1=new JPanel();p2=new JPanel();p21=new JPanel();p211=new JPanel();p212=new JPanel();p213=new JPanel();p22=new JPanel();p3=new JPanel();p31=new JPanel();p4=new JPanel();p41=new JScrollPane(a1);p42=new JPanel();p43=new JPanel();p44=new JPanel();lb1=new JLabel("生产者消费者",JLabel.CENTER);lb2=new JLabel("生产产品的速度");,JLabel.VERTICAL); lb3=new JLabel("消耗产品的速度");,JLabel.VERTICAL); lb4=new JLabel("缓冲区产品数");,JLabel.VERTICAL);lb5=new JLabel("设置生产速度");,JLabel.VERTICAL); lb6=new JLabel("设置消费速度");,JLabel.VERTICAL);lb7=new JLabel("生产消费情况");,JLabel.VERTICAL);b1=new JButton("开始");b1.addActionListener(new Start());b2=new JButton("暂停");b2.addActionListener(new Stop());b3=new JButton("继续");b3.addActionListener(new Continue());b4=new JButton("分析");b4.addActionListener(new ANalysis());b5=new JButton("退出");b5.addActionListener(new Exit());Container container=this.getContentPane(); container.setLayout(new BorderLayout());p0.setLayout(new BorderLayout());p1.setLayout(new FlowLayout());p2.setLayout(new GridLayout(1,2));p21.setLayout(new GridLayout(1,3));p4.setLayout(new GridLayout(2,1));p42.setLayout(new GridLayout(2,1));add(p0);p0.add(p1,BorderLayout.NORTH);p0.add(p2,BorderLayout.CENTER);p0.add(p3,BorderLayout.EAST);p0.add(p4,BorderLayout.SOUTH); p1.add(lb1);p2.add(p21);p21.setBackground(Color.GREEN); p21.add(p211);p21.add(p212);p21.add(p213);p211.add(lb2);p211.add(pb1);p212.add(lb3);p212.add(pb2);p213.add(lb4);p213.add(pb3);p22.add(lb5);p22.add(js1);p22.add(lb6);p22.add(js2);p2.add(p22);p22.setBackground(Color.GRAY);p22.add(lb5);p22.add(js1);p22.add(lb6);p22.add(js2);p3.add(b5);p4.add(p41);p4.add(p42);p42.add(p43);p42.add(p44);p43.add(lb7,JLabel.CENTER);p44.add(b1);p44.add(b2);p44.add(b3);p44.add(b4);p44.add(b5);p1.setBackground(Color.GRAY);p2.setBackground(Color.GRAY);p3.setBackground(Color.GRAY);p4.setBackground(Color.GRAY);p3.setSize(100, 100);p31.setBackground(Color.GRAY);pack();setBackground(Color.lightGray);setVisible(true);Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();设置主界居中显示int screenWidth=screenSize.width;int screenHeight=screenSize.(x,y);}class Start implements ActionListener{public void actionPerformed(ActionEvent e){* 采用管程之后,此处应去掉for(int i=0;i<p;i++)创建生产者线程thread[i]=new Thread(new Producer(Frame,""+(i+1),mutex,full,empty,buffer));for(int i=p;i<p+c;i++)创建消费者线程thread[i]=new Thread(new Consumer(Frame,""+(i+1-p),mutex,full,empty,buffer));for(int i=0;i<p+c;i++)thread[i].start(); 启动所有线程*for(int i=0;i<p;i++)创建生产者线程thread[i]=new Thread(new Producer(frame,"生产者"+(i+1),IM,notfull,notempty,buffer,notfull_count,notempty_count));for(int i=p;i<p+c;i++)创建消费者线程thread[i]=new Thread(new Consumer(frame,"消费者"+(i+1-p),IM,notfull,notempty,buffer,notfull_count,notempty_count));for(int i=0;i<p+c;i++)thread[i].start(); 启动所有线程}}class Stop implements ActionListener{public void actionPerformed(ActionEvent e){for(int i=0;i<p+c;i++)thread[i].suspend(); 阻塞所有线程}}class Continue implements ActionListener{public void actionPerformed(ActionEvent e){for(int i=0;i<p+c;i++)thread[i].resume();}}class ANalysis implements ActionListener{public void actionPerformed(ActionEvent e){new Analysis("分析",buffer,frame);}}class Exit implements ActionListener{public void actionPerformed(ActionEvent e){System.exit(0);}}class winClose extends WindowAdapter{public void windowClosing(WindowEvent e){System.exit(0);}}}********************************************************************** ******************************* Analysis.java 结果分析类package JM;import ng.*;import java.io.*;import java.awt.*;import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*;import Class.Buffer;import JM.JM1;import Class.Buffer;public class Analysis extends JFrame {JPanel p1;JPanel p2;JPanel p3;JScrollPane p4;JPanel p5;Buffer buffer;JLabel lb1;JLabel lb2;JLabel lb3;JLabel lb4;JLabel lb5;JButton b1;JButton b2;Main main;JTextArea yswh;JScrollPane klts;public Analysis(String aa,Buffer buffer,Main main){ super(aa);setLayout(new BorderLayout());this.buffer=buffer;this.main=main;p1=new JPanel();p2=new JPanel();p3=new JPanel();yswh=new JTextArea(150,50);p4=new JScrollPane(yswh);yswh.setText(main.a1.getText());p5=new JPanel();klts=new JScrollPane(yswh);p4=new JPanel();p5=new JPanel();thread[2].getState()lb1=new JLabel("模拟分析结果",JLabel.CENTER);lb2=new JLabel("生产者共生产了"+buffer.getPnumber()+"产品",JLabel.CENTER);lb2=new JLabel("生产者共生产了"+"产品",JLabel.CENTER);lb3=new JLabel(" 消费者共消费了"+buffer.getCnumber()+"产品",JLabel.CENTER);lb3=new JLabel(" 消费者共消费了",JLabel.CENTER);lb4=new JLabel(" 缓冲区剩余的产品数为"+buffer.getValue(),JLabel.CENTER);lb4=new JLabel(" 缓冲区剩余的产品数为",JLabel.CENTER);lb5=new JLabel("生产者消费者各线程此刻所处的状态",JLabel.CENTER);b1=new JButton("确定");b2=new JButton("返回");b1.addActionListener(new queding());b2.addActionListener(new quxiao());add(p1,BorderLayout.NORTH);p1.setLayout(new GridLayout(2, 1));p1.add(lb1);p1.add(p2);p2.add(lb1);p1.add(p3);p3.add(lb2);p3.add(lb3);p3.add(lb4);add(p4,BorderLayout.CENTER );p4.add(lb5);p4.add(klts);add(p5,BorderLayout.SOUTH ); p5.add(b1);p5.add(b2);setBackground(Color.lightGray);setVisible(true);Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();设置主界居中显示int screenWidth=screenSize.width;int screenHeight=screenSize.(x,y);for(int i=0;i<10;i++)yswh.setText(""+this.main.thread[i].getState());for(int i=0;i<10;i++){System.out.print(""+main.thread[i].getState()+"\n");main.a1.append(""+main.thread[i].getState()+"\n");main.a1.append(""+main.thread[i].isAlive()+"\n");}}class queding implements ActionListener{public void actionPerformed(ActionEvent e){dispose();}}class quxiao implements ActionListener{public void actionPerformed(ActionEvent e){dispose();}}}************************************************ **************界面JM1.javapackage JM;import ng.*;import java.io.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.*;public class JM1 extends JFrame {setLayout(new GridLayout(3,3));JPanel p1;JPanel p2; JPanel p21; JPanel p22;JPanel p3; JPanel p31; JPanel p32;JPanel p4; JPanel p41; JPanel p42;JPanel p5;JLabel lb1; JLabel lb2; JLabel lb3; JLabel lb4; JLabel lb5;JTextField f1; JTextField f2; JTextField f3;JTextField f4;JButton b1;JButton b2;public JM1(){}public JM1(String aa){super(aa);setLayout(new GridLayout(4,1));p1=new JPanel();p2=new JPanel();p21=new JPanel();p22=new JPanel();p3=new JPanel();p31=new JPanel();p32=new JPanel();p4=new JPanel();p41=new JPanel();p42=new JPanel();p5=new JPanel();lb1=new JLabel("生产者消费者仿真",JLabel.CENTER);lb2=new JLabel("请输入生产者数目",JLabel.CENTER);lb3=new JLabel("请输入消费者数目",JLabel.CENTER);lb4=new JLabel("请输入缓冲区数目",JLabel.CENTER);lb5=new JLabel("请输入生产者,消费者以及缓冲区的数目,以“确定”结束",JLabel.CENTER);f1=new JTextField(8);f2=new JTextField(8);f3=new JTextField(8);f1.setText("6");f2.setText("5");f3.setText("50");f4=new JTextField();b1=new JButton("确定");b2=new JButton("取消");b1.addActionListener(new queding()); b2.addActionListener(new quxiao());p1.setLayout(new GridLayout(2,1)); p1.add(lb1);p1.add(lb5);p1.add(f1);p2.setLayout(new GridLayout(3,1)); p2.add(p21);p2.add(p31);p2.add(p32);p21.add(lb2);p21.add(f1);p31.add(lb3);p31.add(f2);p32.add(lb4);p32.add(f3);p4.setLayout(new GridLayout(1,2));p4.add(p41);p4.add(p42);p41.add(b1);p41.add(b2);p5.add(lb5);add(p1);add(p2);add(p3);add(p4);add(p5);setBackground(Color.lightGray);setVisible(true);Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();设置参数将界面居中显示int screenWidth=screenSize.width;int screenHeight=screenSize.(x,y);}class queding implements ActionListener{public void actionPerformed(ActionEvent e){dispose();int producer=Integer.parseInt(f1.getText());int consumer=Integer.parseInt(f2.getText());int buffer=Integer.parseInt(f3.getText());new Main("欢迎您使用生产者消费者仿真系统",producer,consumer,buffer);}}class quxiao implements ActionListener{public void actionPerformed(ActionEvent e){f1.setText("");f2.setText("");f3.setText("");}}public static void main(String [] args){JM1 dhk=new JM1("生产者消费者");}}********************************************************** ******************** Buffer.java 缓冲区类package Class;import java.awt.*;import javax.swing.*;import java.awt.event.*;import javax.swing.event.*;import java.util.*;Buffer类Buffer:public class Buffer{public int Bsize; 缓冲区的大小public int Bvalue; 缓冲区中的产品数public int Pnumber;生产者生产的产品计数public int Cnumber;消费者消费的产品计数public Buffer(int size,int value){this.Bsize=size;this.Bvalue=value;}public int getValue() { 获取Value的值return Bvalue;}public int getPnumber() { 获取生产者生产的产品总数return Pnumber;}public int getCnumber() { 获取消费者消费的总产品数值return Cnumber;}}****************************************************************************** Consumer.java 消费者类package Class;import java.awt.*;import javax.swing.*;import java.awt.event.*;import javax.swing.event.*;import JM.Main;import java.util.*;public class Consumer implements Runnable{消费者类private Buffer buffer;缓冲区,即临界资源private String name;消费者的名字private InterfaceModule IM;管程的引用Count aabc,ccba;生产者消费者阻塞的信号量计数private Semaphore notfull;private Semaphore notempty;private Main frame;主界面public Consumer(Main frame,String name,Semaphore mutex,Semaphore full,Semaphore empty,Buffer buffer){public Consumer(Main frame,String name,InterfaceModule im,Semaphore notfull,Semaphore notempty,Buffer buffer,Count aabc,Count ccba){this.buffer=buffer;this.notempty=notempty;消费者阻塞后移入队列的信号量this.notfull=notfull;生产者阻塞后移入队列的信号量this.IM=im;=name;this.aabc=aabc;为消费者阻塞个数计数ba=ccba;为生产者阻塞的个数计数值this.frame=frame;}public void run(){while(true){this.IM.enter(""+);消费者线程调用管程System.out.print(+"已经进入了管程\n");frame.a1.append(+"已经进入了管程\n");if(buffer.Bvalue==0)缓冲区为空,即没有产品,消费者线程调用Wait等待this.IM.Wait(notempty,ccba,);notempty消费者阻塞后移入队列的信号量,初值为0 ccba为消费者阻塞个数计数buffer.Bvalue--;缓冲区中的产品数减1umber++;消费者消费的总次数计数System.out.print(+"消耗了一件产品"+buffer.Bvalue+"\n");frame.a1.append(+" 从缓冲区取走并消耗一件产品此刻缓冲区的产品数为"+buffer.Bvalue+" 缓冲区总容量为"+buffer.Bsize+"\n");frame.a1.append(+" 生产了一件产品并放入缓冲区此刻缓冲区的产品数为"+buffer.Bvalue+" 缓冲区总容量为"+buffer.Bsize+"\n");if(buffer.Bvalue>=0){frame.pb2.setValue(frame.js2.getValue());frame.pb3.setValue(buffer.Bvalue);frame.pb3.setString(String.valueOf(buffer.Bvalue));}this.IM.Signal(notfull,aabc,);唤醒等待的生产者notfull为生产者阻塞后移入队列的信号量aabc为生产者阻塞的个数计数值this.IM.leave();System.out.print(+"离开管程\n");frame.a1.append(+"离开管程\n");try{Thread.sleep(500*(10-frame.js2.getValue()));}catch(InterruptedException e){}}while(true){*full.p();mutex.p();frame.a1.insert(""+"消费者"+name+" 从缓冲区中取出了一件产品\n",0);frame.a1.insert(" ... .... \n",0);frame.a1.insert(" ... .... ... ...\n",0);umber++;buffer.Bvalue--;Buffer的数据数减1if(buffer.Bvalue>=0){frame.pb2.setValue(frame.js2.getValue());frame.pb3.setValue(buffer.Bvalue);frame.pb3.setString(String.valueOf(buffer.Bvalue));}mutex.v();empty.v();try{if(frame.js2.getValue()==0)Thread.sleep(20000);elseThread.sleep(100*(10-frame.js2.getValue()));}catch(InterruptedException e){}*}}}*********************************************************** ********************************** Count.java 计数package Class;public class Count {public int Cvalue;public Count(int aa) {TODO Auto-generated constructor stubthis.Cvalue=aa;}public void setValue(int aaa){this.Cvalue=aaa;}public int getValue(){return this.Cvalue;}}**************************************************************************************** InterfaceModule.java 管程类package Class;import JM.Main;public class InterfaceModule {private Semaphore mutex;进程调用管程之前所使用的互斥信号量private Semaphore next;发出signal操作的线程挂起自己的信号量int next_count;在next上等待的线程数Main frame;Count x_count;public Count count;public InterfaceModule(Main frame) {TODO Auto-generated constructor stubthis.count=count;this.frame=frame;mutex=new Semaphore(1,frame);初始化互斥信号量next=new Semaphore(0,frame);next_count=0;this.x_count=x_count;}public void enter(String s){mutex.p(s+"因无法进入管程而");互斥的进入管程frame.a1.append(""+s+"已经进入管程\n");System.out.print("\n进入管程\n");}public void leave(String s1){frame.a1.append(s1+"当前正在执行管程的leave操作\n");if(next_count>0)判断有否发出signal操作的线程{next.v(s1+"释放一个因发出signal操作而阻塞自己的线程\n");若有就释放一个frame.a1.append("释放一个因发出signal操作而阻塞自己的线程\n");}else{mutex.v(s1+"离开管程\n"+"开放管程");否则开放管程frame.a1.append("线程即将要离开管程,在离开之前开放管程\n");}System.out.print("\n离开管程\n");}public void Wait(Semaphore x_sem,Count x_count,String s1){x_count.Cvalue++;等待资源的线程数加1,初始值为0frame.a1.append();System.out.print("Wait\n");frame.a1.append(s1+"执行Wait操作因资源不可用而该线程即将阻塞自己!!(缓冲区已满或者已为空)\n在阻塞自己之前,先判断是否有发出signal 操作的线程。
操作系统之进程(生产者---消费者)实验报告
操作系统实验报告——生产者和消费者问题姓名:学号:班级:一、实验内容1、模拟操作系统中进程同步和互斥;2、实现生产者和消费者问题的算法实现;二、实验目的1、熟悉临界资源、信号量及PV操作的定义与物理意义;2、了解进程通信的方法;3、掌握进程互斥与进程同步的相关知识;4、掌握用信号量机制解决进程之间的同步与互斥问题;5、实现生产者-消费者问题,深刻理解进程同步问题;三、实验题目在Windows操作系统下用C语言实现经典同步问题:生产者—消费者,具体要求如下:(1)一个大小为10的缓冲区,初始状态为空。
(2)2个生产者,随机等待一段时间,往缓冲区中添加数据,若缓冲区已满,等待消费者取走数据之后再添加,重复10次。
页脚内容1(3)2个消费者,随机等待一段时间,从缓冲区中读取数据,若缓冲区为空,等待生产者添加数据之后再读取,重复10次。
四、思想本实验的主要目的是模拟操作系统中进程同步和互斥。
在系统进程并发执行异步推进的过程中,由于资源共享和进程间合作而造成进程间相互制约。
进程间的相互制约有两种不同的方式。
(1)间接制约。
这是由于多个进程共享同一资源(如CPU、共享输入/输出设备)而引起的,即共享资源的多个进程因系统协调使用资源而相互制约。
(2)直接制约。
只是由于进程合作中各个进程为完成同一任务而造成的,即并发进程各自的执行结果互为对方的执行条件,从而限制各个进程的执行速度。
生产者和消费者是经典的进程同步问题,在这个问题中,生产者不断的向缓冲区中写入数据,而消费者则从缓冲区中读取数据。
生产者进程和消费者对缓冲区的操作是互斥,即当前只能有一个进程对这个缓冲区进行操作,生产者进入操作缓冲区之前,先要看缓冲区是否已满,如果缓冲区已满,则它必须等待消费者进程将数据取出才能写入数据,同样的,消费者进程从缓冲区读取数据之前,也要判断缓冲区是否为空,如果为空,则必须等待生产者进程写入数据才能读取数据。
在本实验中,进程之间要进行通信来操作同一缓冲区。
生产者与消费者的问题-----操作系统课程设计
闽江学院计算机系网络操作系统课程设计设计内容:进程机制与并发程序设计——linux下生产者与消费者的问题实现目录:一、设计内容 (3)二、设计思想 (4)三、系统结构 (5)四、PV操作代码 (5)五、C++程序代码 (6)六、运行结果截图 (9)七、参考文献 (11)八、实验总结 (11)一、设计内容进程机制与并发程序设计————linux下生产者与消费者的问题实现1.实验目的(1)掌握基本的同步互斥算法,理解生产者和消费者同步的问题模型。
(2)了解linux中多线程的并发执行机制,线程间的同步和互斥。
2、实验环境:C/C++语言编译器3、实验要求(1)创建生产者和消费者线程在linux环境下,创建一个控制台进程,在此进程中创建n个线程来模拟生产者或者消费者。
这些线程的信息由本程序定义的“测试用例文件”中予以指定。
该文件的格式和含义如下:31 P 32 P 43 C4 14 P 25 C 3 1 2 4第一行说明程序中设置几个临界区,其余每行分别描述了一个生产者或者消费者线程的信息。
每一行的各字段间用Tab键隔开。
不管是消费者还是生产者,都有一个对应的线程号,即每一行开始字段那个整数。
第二个字段用字母P或者C区分是生产者还是消费者。
第三个字段表示在进入相应线程后,在进行生产和消费动作前的休眠时间,以秒计时;这样做的目的是可以通过调整这一列参数,控制开始进行生产和消费动作的时间。
如果是代表生产者,则该行只有三个字段。
如果代表消费者,则该行后边还有若干字段,代表要求消费的产品所对应的生产者的线程号。
所以务必确认这些对应的线程号存在并且该线程代表一个生产者。
(2)生产和消费的规则在按照上述要求创建线程进行相应的读写操作时,还需要符合以下要求:①共享缓冲区存在空闲空间时,生产者即可使用共享缓冲区。
②从上边的测试数据文件例子可以看出,某一生产者生产一个产品后,可能不止一个消费者,或者一个消费者多次地请求消费该产品。
操作系统课程设计-生产者消费者问题linux
#include<stdio.h>#include<pthread.h>#define MAX 30#define BUFFER_SIZE 20pthread_mutex_t the_mutex,the_main,the_p;pthread_cond_t condc,condp;int buffer[BUFFER_SIZE];int in=0;int out=0;int counter=0;int flg[30]={0};int k=0;int p=0;void *producer1(void* s){pthread_mutex_lock(&the_main);pthread_mutex_unlock(&the_main);int proid=(int)s;int i;for(i=1;i<=MAX;i++){pthread_mutex_lock(&the_mutex);while(counter==BUFFER_SIZE){printf("%d号生产者wait...\n",proid);pthread_cond_wait(&condp,&the_mutex);printf("%d号生产者唤醒...\n",proid);}buffer[in]=1;printf("%d号生产者生产1放入%d中\n",proid,in);in=(in+1)%BUFFER_SIZE;counter++;pthread_cond_signal(&condc);pthread_mutex_unlock(&the_mutex);}pthread_mutex_lock(&the_p);p++;printf("%d号生产者线程结束\n",proid);pthread_mutex_unlock(&the_p);return 0;}void *consumer1(void* s){pthread_mutex_lock(&the_main);pthread_mutex_unlock(&the_main);int conid=(int)s;int j=1;int k=0;while(1){pthread_mutex_lock(&the_mutex);if(p==30&&counter==0){pthread_mutex_unlock(&the_mutex);break;}// printf("p=%d counter=%d\n",p,counter);while(counter==0){if(p==30&&counter==0){pthread_mutex_unlock(&the_mutex);break;}printf(" %d号消费者wait...\n",conid); pthread_cond_wait(&condc,&the_mutex);printf("%d号消费者唤醒...\n",conid);}if(buffer[out]==4){printf("%d号消费者在%d处消费%d counter=%d p=%d\n",conid,out);buffer[out]=0;out=(out+1)%BUFFER_SIZE;counter--;pthread_cond_signal(&condp);}if(buffer[out]==1&&flg[conid]==0){flg[conid]=1;printf("%d号消费者在%d处消费%d counter=%d p=%d\n",conid,out);for(j=1;j<=29;j=j+2)if(flg[j]==1)k++;if(k==15){k=0;for(j=1;j<=29;j++)flg[j]=0;buffer[out]=0;out=(out+1)%BUFFER_SIZE;counter--;pthread_cond_signal(&condp);}elsek=0;}else{pthread_cond_signal(&condc);}pthread_mutex_unlock(&the_mutex);}printf("%d消费者线程结束\n",conid);pthread_exit(0);}int main(int argc,char **argv){int j;pthread_t pro[31],con[31];pthread_mutex_init(&the_mutex,0);pthread_mutex_init(&the_main,0);pthread_cond_init(&condc,0);pthread_cond_init(&condp,0);pthread_mutex_lock(&the_main);for(j=1;j<=10;j=j+2){pthread_create(&pro[j],0,producer1,(void*)j);pthread_create(&con[j],0,consumer1,(void*)j);}printf("线程创建完成\n");pthread_mutex_unlock(&the_main);for(j=1;j<=30;j++){pthread_join(con[j],0);}printf("消费者线程结束\n");pthread_mutex_destroy(&the_main);pthread_cond_destroy(&condc);pthread_cond_destroy(&condp);pthread_mutex_destroy(&the_mutex);。
操作系统实验报告生产者消费者问题
《操作系统》实验报告2016年1月8日指导教师对实验报告的评语成绩:指导教师签字:年月日一、设计目标●完成N个生产者和M个消费者线程之间的并发控制,N、M不低于30,数据发送和接收缓冲区尺寸不小于20个(每个产品占据一个)。
●其中生产者线程1、3、5、7、9生产的产品供所有奇数编号的消费者线程消费,只有所有奇数编号的消费者线程都消费后,该产品才能从缓冲区中撤销。
●其中生产者线程2、4、6、8、10生产的产品所有偶数编号的消费者线程都可消费,任一偶数编号消费者线程消费该消息后,该产品都可从缓冲区中撤销。
●其中11-20号生产者线程生产的产品仅供对应编号的消费者线程消费。
●其他编号生产者线程生产的产品可由任意的消费者线程消费。
●每个生产线程生产30个消息后结束运行。
如果一个消费者线程没有对应的生产者线程在运行后,也结束运行。
所有生产者都停止生产后,如果消费者线程已经没有可供消费的产品,则也退出运行。
二、背景知识说明原理利用进程间共享的信号量、互斥锁等控制线程同步。
相关函数说明pthread_create():创建一个线程pthread_join():阻塞当前的线程,直到另外一个线程运行结束pthread_mutex_init():初始化互斥锁pthread_mutex_lock():占有互斥锁(阻塞操作)pthread_mutex_unlock():释放互斥锁sem_wait():获取信号量sem_post():释放信号量三、设计设计环境Linux操作系统(ubuntu12.04)gcc 4.6c语言Posix线程库编译命令:gcc consumer.c -lpthread -o consumer概要设计及详细设计图注释:(1)图:主函数流程(2)图:生产者流程(3)图:消费者流程(1)图(2) 图(3)图重要代码注释:#include<stdio.h>#include<malloc.h>#include<pthread.h>#include<semaphore.h>#define BUFFER_SIZE 30#define OVER (-1)struct Product{int tid;int data;};struct producers{//定义生产者条件变量结构struct Product buffer[BUFFER_SIZE];//缓冲区sem_t sem_read; // 读信号量sem_t sem_write; // 写信号量pthread_mutex_t wlock; // 缓冲区写锁pthread_mutex_t rlock; // 缓冲区读锁pthread_mutex_t lock; // thread_count的读写锁int readpos , writepos;//读写位置};struct producers buffer;int thread_count = 30; //存活生产者计数//用于在线程内部标识线程IDint ids[30] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30}; int count = 0; // 计数消费产品数量int pcount = 0; // 计数生产产品数量void init(){//初始化相关锁和变量以及信号量buffer.readpos = 0;buffer.writepos = 0;//写信号量比缓冲区小1,防止缓冲区满和缓冲区空分不清sem_init(&buffer.sem_write, 0, BUFFER_SIZE-1);sem_init(&buffer.sem_read, 0, 0);pthread_mutex_init(&buffer.wlock, NULL);pthread_mutex_init(&buffer.rlock, NULL);pthread_mutex_init(&buffer.lock, NULL);}void put(int tid, int data){//缓冲区中放入一个数据sem_wait(&buffer.sem_write);//生产前先加锁,已防止其他线程同时生产pthread_mutex_lock(&buffer.wlock);buffer.buffer[buffer.writepos].tid = tid;buffer.buffer[buffer.writepos].data = data;buffer.writepos ++;++ pcount;if( buffer.writepos >= BUFFER_SIZE )buffer.writepos = 0;pthread_mutex_unlock(&buffer.wlock);sem_post(&buffer.sem_read);}//读数据并移走struct Product * get(int tid){struct Product * produce = NULL;//消费前先上锁,以防止其他线程同时消费pthread_mutex_lock(&buffer.rlock);// 如果生产者线程没有全部退出,或者缓冲区内仍有产品,则说明可以尝试去获取产品if(thread_count > 0 || buffer.readpos != buffer.writepos){//从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法sem_wait( &buffer.sem_read );int pos = buffer.readpos;// 在已有产品中迭代,查找适合的产品while(pos != buffer.writepos){int id = buffer.buffer[pos].tid;if(id >10 && id <=20 && tid == id){ //如果产品是的生产者线程号10<id<=20 则可以供和它的线程号相同的消费者线程消费produce = (struct Product *)malloc(sizeof(struct Product));produce->tid = id;produce->data = buffer.buffer[pos].data;break;}else if(id <= 10 && (id%2 == tid%2)){ //如果产品是的生产者线程号<=10 则可以供和它的线程号奇偶性相同的消费者消费produce = (struct Product *)malloc(sizeof(struct Product));produce->tid = id;produce->data = buffer.buffer[pos].data;break;}else if(id > 20){ //如果产品是的生产者线程号>20则可以供任何消费者消费produce = (struct Product *)malloc(sizeof(struct Product));produce->tid = id;produce->data = buffer.buffer[pos].data;break;}pos = (pos+1)%BUFFER_SIZE;}if( produce ){ //如果取得了产品,消费计数+1,将在队头的元素覆盖到被取走的位置++ count;buffer.buffer[pos].tid = buffer.buffer[buffer.readpos].tid;buffer.buffer[pos].data = buffer.buffer[buffer.readpos].data;++ buffer.readpos;}if( buffer.readpos >= BUFFER_SIZE )buffer.readpos = 0;//如果取得了产品则释放一个缓冲区可写的信号量,否则释放一个可读的信号量if( produce )sem_post(&buffer.sem_write);elsesem_post(&buffer.sem_read);pthread_mutex_unlock(&buffer.rlock);}elsepthread_mutex_unlock(&buffer.rlock);return produce;}void *producer(void *data){ //每个线程循环生产30个产品int tid = *((int *)data);int n;for(n = 1; n <= 30; n++){printf("producer %d product %d \n", tid, n);put(tid, n);}// 每退出一个生产者线程后,thread_count 减1pthread_mutex_lock(&buffer.lock);-- thread_count;pthread_mutex_unlock(&buffer.lock);return NULL;}void *consumer(void * data){int tid = *((int *)data);struct Product *d = NULL;while(1){d = get(tid);if( d ) {printf("consumer %d consum %d from Producer %d \n", tid, d->data,d->tid);free(d);}pthread_mutex_lock(&buffer.lock);// 当所有生产者线程已退出,且缓冲区内已没有该线程可消费的产品时,退出该线程if(d == NULL && thread_count == 0 ){pthread_mutex_unlock(&buffer.lock);break;}elsepthread_mutex_unlock(&buffer.lock);}return NULL;}int main(void){pthread_t th_a[30], th_b[30];void *retval;init(&buffer);int i;for(i = 0; i<30; ++i){ // 创建生产者和消费者pthread_create(&th_a[i], NULL, producer, &ids[i]);pthread_create(&th_b[i], NULL, consumer, &ids[i]);}for(i = 0; i<30; ++i){ // 将线程加入到主线程组pthread_join(th_a[i], &retval);pthread_join(th_b[i], &retval);}printf("product %d products\n", pcount);printf("consume %d products\n", count);return 0;}四、测试测试数据文件格式测试数据由程序内部生成运行结果分析运行./consumer cat > output.txt 将输出结果保存在output.txt中待分析。
操作系统生产者与消费者课程设计
《操作系统》课程设计生产者和消费者问题系院:计算机科学系学生姓名:吴伟学号:01专业:软件工程年级:0701B完成日期:2009年11月指导教师:刘栓二、课程设计的内容及其要求1.实验内容以生产者/消费者模型为依据,在Windows 2000环境下创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。
2.实验要求学习并理解生产者/消费者模型及其同步/互斥规则;学习了解Windows同步对象及其特性;熟悉实验环境,掌握相关API的使用方法;设计程序,实现生产者/消费者进程(线程)的同步与互斥;提交实验报告。
五、正文1、实验程序的结构图(流程图);开始Wait ProductsWait BufferConsumeProduceWhile consumeWhile produce结束2、数据结构及信号量定义的说明;(1) CreateThread功能——创建一个在调用进程的地址空间中执行的线程格式HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParamiter,DWORD dwCreationFlags,Lpdword lpThread );参数说明lpThreadAttributes——指向一个LPSECURITY_ATTRIBUTES(新线程的安全性描述符)。
dwStackSize——定义原始堆栈大小。
lpStartAddress——指向使用LPTHRAED_START_ROUTINE类型定义的函数。
lpParamiter——定义一个给进程传递参数的指针。
dwCreationFlags——定义控制线程创建的附加标志。
lpThread——保存线程标志符(32位)(2) CreateMutex功能——创建一个命名或匿名的互斥量对象格式HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,LPCTSTR lpName);参数说明lpMutexAttributes——必须取值NULL。
操作系统实验 生产者与消费者问题
实验一生产者和消费者问题1、程序流程图2、源代码#include <windows.h>#include <iostream>const unsigned short SIZE_OF_BUFFER = 10;unsigned short ProductID = 0;unsigned short ConsumeID = 0;unsigned short in = 0;unsigned short out = 0;int g_buffer[SIZE_OF_BUFFER];bool g_continue = true;HANDLE g_hMutex;HANDLE g_hFullSemaphore;HANDLE g_hEmptySemaphore;DWORD WINAPI Producer(LPVOID);DWORD WINAPI Consumer(LPVOID);int main(){ g_hMutex = CreateMutex(NULL,FALSE,NULL);g_hFullSemaphore = CreateSemaphore(NULL,SIZE_OF_BUFFER-1,SIZE_OF_BUFFER-1,NULL);g_hEmptySemaphore = CreateSemaphore(NULL,0,SIZE_OF_BUFFER-1,NULL);const unsigned short PRODUCERS_COUNT = 3;const unsigned short CONSUMERS_COUNT = 1;const unsigned short THREADS_COUNT = PRODUCERS_COUNT+CONSUMERS_COUNT;HANDLE hThreads[PRODUCERS_COUNT];DWORD producerID[CONSUMERS_COUNT];DWORD consumerID[THREADS_COUNT];for (int i=0;i<PRODUCERS_COUNT;++i){hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);if (hThreads[i]==NULL) return -1;}for ( i=0;i<CONSUMERS_COUNT;++i){hThreads[PRODUCERS_COUNT+i]=CreateThread(NULL,0,Consumer,NULL,0,&consumerID[i]);if (hThreads[i]==NULL) return -1;}while(g_continue){if(getchar()){ //按回车后终止程序运行g_continue = false;}}return 0;}void Produce(){ std::cerr << "Producing " << ++ProductID << " ... ";std::cerr << "Succeed" << std::endl;}void Append(){ std::cerr << "Appending a product ... ";g_buffer[in] = ProductID;in = (in+1)%SIZE_OF_BUFFER;std::cerr << "Succeed" << std::endl;for (int i=0;i<SIZE_OF_BUFFER;++i){std::cout << i <<": " << g_buffer[i];if (i==in) std::cout << " <-- 生产";if (i==out) std::cout << " <-- 消费";std::cout << std::endl;}}void Take(){ std::cerr << "Taking a product ... ";ConsumeID = g_buffer[out];out = (out+1)%SIZE_OF_BUFFER;std::cerr << "Succeed" << std::endl;for (int i=0;i<SIZE_OF_BUFFER;++i){std::cout << i <<": " << g_buffer[i];if (i==in) std::cout << " <-- 生产";if (i==out) std::cout << " <-- 消费";std::cout << std::endl; }}void Consume(){ std::cerr << "Consuming " << ConsumeID << " ... ";std::cerr << "Succeed" << std::endl;}DWORD WINAPI Producer(LPVOID lpPara){ while(g_continue){WaitForSingleObject(g_hFullSemaphore,INFINITE);WaitForSingleObject(g_hMutex,INFINITE);Produce();Append();Sleep(1500);ReleaseMutex(g_hMutex);ReleaseSemaphore(g_hEmptySemaphore,1,NULL);}return 0;}DWORD WINAPI Consumer(LPVOID lpPara){ while(g_continue){WaitForSingleObject(g_hEmptySemaphore,INFINITE);WaitForSingleObject(g_hMutex,INFINITE);Take();Consume();Sleep(1500);ReleaseMutex(g_hMutex);ReleaseSemaphore(g_hFullSemaphore,1,NULL);}return 0;}3、实验结果3、实验心得通过做生产者消费者问题这个实验,让我更加明确了两者之间的联系和基本的同步互斥算法,了解多线程并发执行机制是怎样的,线程间的同步和互斥又是怎样的,还有缓冲区的在其中作用是什么。
操作系统实验报告 经典的生产者—消费者问题
实验二经典的生产者—消费者问题一、目的实现对经典的生产者—消费者问题的模拟,以便更好的理解经典进程同步问题。
二、实验内容及要求编制生产者—消费者算法,模拟一个生产者、一个消费者,共享一个缓冲池的情形。
1、实现对经典的生产者—消费者问题的模拟,以便更好的理解此经典进程同步问题。
生产者-消费者问题是典型的PV操作问题,假设系统中有一个比较大的缓冲池,生产者的任务是只要缓冲池未满就可以将生产出的产品放入其中,而消费者的任务是只要缓冲池未空就可以从缓冲池中拿走产品。
缓冲池被占用时,任何进程都不能访问。
2、每一个生产者都要把自己生产的产品放入缓冲池,每个消费者从缓冲池中取走产品消费。
在这种情况下,生产者消费者进程同步,因为只有通过互通消息才知道是否能存入产品或者取走产品。
他们之间也存在互斥,即生产者消费者必须互斥访问缓冲池,即不能有两个以上的进程同时进行。
三、生产者和消费者原理分析在同一个进程地址空间内执行两个线程。
生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。
消费者线程从缓冲区中获得物品,然后释放缓冲区。
当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放一个空缓冲区。
当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻挡,直到新的物品被生产出来。
四、生产者与消费者功能描述:生产者功能描述:在同一个进程地址空间内执行两个线程。
生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。
当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。
消费者功能描述:消费者线程从缓冲区获得物品,然后释放缓冲区,当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
五、实验环境操作系统环境:Windows系统。
编程语言:C#。
六、生产者与消费者的思路和设计1、程序流程图(1) 生产者(2) 消费者2、主要程序代码//初始化变量private void Form1_Load(object sender, EventArgs e){mutex = 1; //互斥信号量full = 0; //缓冲池中满缓冲区的数量empty = 5;//缓冲池中空缓冲区的数量count1 = 0;//生产的产品数目i = 0;lb_mutex.Text = "1";lb_full.Text = "0";lb_empty.Text = "5";}//消费者从缓冲区中消费一个产品private void consumer_Click(object sender, EventArgs e){if (full > 0){ //消费者已进入互斥临界区if (mutex == 1) //申请进入临界区{mutex = 0; //消费者已进入互斥临界区lb_mutex.Text = "0";timer_consumer.Enabled = true;//启动消费者消费缓冲区产品}else{MessageBox.Show("缓冲区被占用,请等待。
操作系统生产者消费者问题C语言
《操作系统概念》第七版中的实验项目:生产者消费者问题。
本程序中,main()函数需要三个参数:主线程休眠时间;生产者线程数;消费者线程数。
各线程的休眠等待时间是随机的。
程序代码:#include〈stdio。
h>#include<stdlib。
h〉#include<time。
h>#include〈windows.h>#define BUFFER_SIZE 5typedef int buffer_item;struct v{int i;};buffer_item buffer[BUFFER_SIZE+1];buffer_item front=0,rear=0;HANDLE mutex,empty,full;int insert_item(buffer_item item){/*insert item into bufferreturn 0 if successful,otherwisereturn —1 indicating an error condition*/if((rear+1)%(BUFFER_SIZE+1)==front)return 1;buffer[rear]=item;rear=(rear+1)%(BUFFER_SIZE+1);return 0;}int remove_item(buffer_item *item){/*remove an object from bufferplacing it in itemreturn 0 if successful,otherwisereutrn —1 indication an error condition */if(front == rear)return 1;*item=buffer[front];front=(front+1)%(BUFFER_SIZE+1);return 0;}DWORD WINAPI producer(PVOID Param){int rand1;struct v data=*(struct v *)Param;srand((unsigned)time(0));while (1){Sleep(rand()%101*10);WaitForSingleObject(empty,INFINITE);WaitForSingleObject(mutex,INFINITE);rand1 =rand();printf(”producer has producerd %d By %d\n",rand1,data。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
枣庄学院信息科学与工程学院课程设计任务书题目:生产者-消费者问题的实现姓名:学号:专业:计算机科学与技术课程:操作系统指导教师:刘彩霞职称:讲师完成时间: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。
消费者函数执行P操作,信号量full减1,判断是否有数据,有则互斥的访问缓冲区并取走数据,然后释放缓冲区,执行V操作,empty信号量加1。
第3章程序详细设计3.1程序模块设计该实验主要分为三大模块:1.主程序,创建并控制程序的流程,其中控制线程的活动以及信号量的操作,如图3-1-1所示;2.生产者模块:生产者对缓冲区的操作,如图3-1-2所示;3.消费者模块:消费者对缓冲区的操作,如图3-1-3所示。
程序相关模块的流程图图3-1-1 主程序图3-1-2生产者图3-1-3消费者3.2程序代码结构通过分析,我们已经了解到了可以采用信号量来解决n个进程的临界区问题,这n个进程共享一个信号量mutex(mutual exclusion),并初始化为1。
每个进程P的组织结构如下图。
i由于本系统我们研究的是有限缓冲区(Bounded-Buffer)的生产者消费者问题。
而且根据初始条件可知,该缓冲区内有20个缓冲项,每个缓冲项存储一个整形数。
信号量mutex提供了对缓冲池访问的互斥要求,并初始化为1。
信号量empty和full分别用来表示空缓冲项和满缓冲项的数量。
信号量empty初始化为20,而信号量full初始化为0;生产者进程和消费者进程的代码如图。
注意生产者和消费者之间的对称性可以这样来理解代码:生产者为消费者生产满缓冲项,或消费者为生产者生产空缓冲项。
实验结果如截图所示:图4-1 实验结果截图进程的同步与互斥是操作系统课程中非常重要的一部分内容。
通过本次课程设计,我和我的组员不仅学会了使用信号量机制解决有限缓冲区的生产者消费者问题,而且对Linux系统下多线程编程有了更深入的了解。
虽然实验以前我已经对信号量机制解决进程间同步问题的原理有了很清楚的认识,但是此次课程设计中仍然遇到了很多问题,如Linux系统下各种系统调用以及函数的各种参数,都花费了我很多时间去网上看各种资料——虽然Linux 系统中可以很方便的阅读源代码以及使用man命令进行相应指令的查看,但是全英文的资料让人看了不免有些发怵,看来还要多多加强计算机专业英语的学习,以后便可以在Linux系统中查看各种帮助文件。
另一个问题就是在编译的时候遇到的,刚开始用gcc –o main main.c 进行编译的时候总是提示出错,后来查了相关资料才知道pthread 库不是 Linux 系统默认的库,连接时需要使用静态库libpthread.a,所以在使用pthread_create()等函数时,需要链接该库才能编译通过。
以前再用Windows IDE 进行编程的时候基本上不会遇到这样的问题,看来的确IDE为我们做了很多工作,隐藏了一些技术细节,有时候隐藏这些细节虽然可以方便我们,却让我们离真相越来越远。
最近使用Linux进行相关的编程操作,感悟还是挺多的。
Windows下的层层封装的确让我们感到很方便,但同时也让我们编程变得越来越不灵活。
因为我们不用再去了解底层的东西因此一遇到问题就会束手无策。
这段时间一直用Linux进行编程,感觉很方便,跟我以前想象地完全不一样,而且我掌握了不少命令,比我以前用鼠标操作的时候快多了,而且在Bash下可以用Ctrl+Z随时中止正在运行的进程或命令,再用fg %id 重新运行。
Linux下的编程也很方便,我还了解了Makefile的编写方法,在多文件编程的时候可以极高地提高效率。
总之,我之后会加强专业英语的学习,以便更好的利用Linux操作系统进行编程之路的学习。
附录:实验代码#include<stdio.h>#include<stdlib.h>#include<string.h>#include<pthread.h>#include<semaphore.h>#include<signal.h>#define num_producer 3#define num_consumer 3 //由于题目要求生产者和消费者各有两个以上,故此处均定为3个#define BUFFER_SIZE 20 //定义缓冲区的大小,按题目要求为20int NUM=1; //题目要求放入/取出的数据项按增序设定为1-20,因此定义此全局变量int buffer[BUFFER_SIZE];int nextp=0,nextc=0;sem_t empty,full,mutex;//主函数int main(){int i;signal(SIGALRM,handler);sem_init(&empty,0,BUFFER_SIZE);sem_init(&full,0,0);sem_init(&mutex,0,1);for(i=0;i<BUFFER_SIZE;i++) buffer[i]=0;for(i=0;i<num_producer;i++)pthread_create(&threads_p[i],NULL,(void*)producer_thread,(void*)(i+1));for(i=0;i<num_consumer;i++)pthread_create(&threads_c[i],NULL,(void*)consumer_thread,(void *)(i+1)); for(i=0;i<num_producer;i++) pthread_join(threads_p[i],NULL);for(i=0;i<num_consumer;i++) pthread_join(threads_c[i],NULL);sem_destroy(&empty);sem_destroy(&full);sem_destroy(&mutex);return 0;}//消费者代码void *consumer_thread(void *tid){int i;pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);while(1){sem_wait(&full);srand((int)time(NULL)*(int)tid);sem_wait(&mutex);printf("消费者标识:%d\t指针位置:%d\t\n",(int)tid,nextc);buffer[nextc]=0;nextc=(nextc+1)%20;printf("缓冲区:");for(i=0;i<BUFFER_SIZE;i++){printf("%3d",buffer[i]);}printf("\n");sem_post(&mutex);sem_post(&empty);srand((int)time(NULL)*(int)tid);sleep(1);}return ((void*)0);}//生产者代码void *producer_thread(void *tid){int i;pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); while(1){sem_wait(&empty);srand((int)time(NULL)*(int)tid);sleep(1);while((nextp+1)%20==nextc);sem_wait(&mutex);if(NUM>20) NUM=1;//如果大于20,NUM重新为1buffer[nextp]=(NUM++);nextp=(nextp+1)%20;if(nextp==0){printf("生产者标识:%d\t指针位置:19\t\n",(int)tid);}else{printf("生产者标识:%d\t指针位置:%d\t\n",(int)tid,nextp-1);}printf("缓冲区:");for(i=0;i<BUFFER_SIZE;i++){printf("%3d",buffer[i]);}printf("\n");sem_post(&mutex);sem_post(&full);srand((int)time(NULL)*(int)tid); }return ((void*)0);}。