生产者消费者问题linux代码

合集下载

操作系统实验三 生产者——消费者问题

操作系统实验三 生产者——消费者问题

操作系统实验三:生产者——消费者问题一、基本信息xxx 711103xx 2012年4月29日二、实验目的通过实验,掌握Windows和Linux环境下互斥锁和信号量的实现方法,加深对临界区问题和进程同步机制的理解,同时巩固利用Windows API和Pthread API进行多线程编程的方法。

三、实验内容1. 在Windows操作系统上,利用Win32 API提供的信号量机制,编写应用程序实现生产者——消费者问题。

2. 在Linux操作系统上,利用Pthread API提供的信号量机制,编写应用程序实现生产者——消费者问题。

3. 两种环境下,生产者和消费者均作为独立线程,并通过empty、full、mutex 三个信号量实现对缓冲进行插入与删除。

4. 通过打印缓冲区中的内容至屏幕,来验证应用程序的正确性。

四、实验步骤1. 创建3个信号量:Mutex、Full、Empty2. 主程序创建10个生产者线程和10个消费者线程,之后休眠一段时间3. 生产者线程中,休息一段2s后,生产一个0~10的随机数放入缓冲区里。

利用信号量Mutex产生对缓冲区使用的互斥功能,利用Empty和Full信号量来对缓冲区进行增加项4. 消费者线程中,休息4s时间后,消费一个缓冲区的数据。

利用信号量Mutex产生对缓冲区使用的互斥功能,利用Empty和Full信号量来对缓冲区进行增加项5. 主程序执行一段时间后,结束整个程序五、主要数据结构及其说明产品数量最大值const int MAX_SIZE = 10;缓冲区:int buffer[BUFFER_SIZE];int front; int rear; bool full;三个互斥信号量:HANDLE Mutex; HANDLE Full; HANDLE Empty;有关操作:用WaitForSingleSignal函数可以获得一个Mutex的所有权,类似于P 操作,而ReleaseMutex函数可以释放一个Mutex的所有权,类似于V 操作。

操作系统生产者消费者问题代码

操作系统生产者消费者问题代码

#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<<"发出消费请求。

生产者与消费者问题的模拟实现

生产者与消费者问题的模拟实现

操作系统课程设计报告专业计算机科学与技术学生姓名郑伟班级BM计算机091 学号0951401123指导教师李先锋完成日期2011年12月31日博雅学院题目:生产者与消费者问题的模拟实现一、设计目的本课程设计是学习完“操作系统原理”课程后进行的一次全面的综合训练,通过课程设计,更好地掌握操作系统的原理及实现方法,加深对操作系统基础理论和重要算法的理解,加强学生的动手能力。

二、设计内容1)概述用多进程同步方法解决生产者-消费者问题,C或C++语言实现。

设计目的:通过研究Linux 的进程机制和信号量实现生产者消费者问题的并发控制。

说明:有界缓冲区内设有20个存储单元,放入/取出的数据项设定为1-20这20个整型数。

设计要求:(1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容,当前指针位置和生产者/消费者县城的标识符。

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

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

(提示:有界缓冲区可用数组实现)2)设计原理计算机系统中的每个进程都可以消费或生产某类资源。

当系统中某一进程使用某一资源时,可以看作是消耗,且该进程称为消费者。

而当某个进程释放资源时,则它就相当一个生产者。

因为有多个缓冲区,所以生产者线程没有必要在生成新的数据之前等待最后一个数据被消费者线程处理完毕。

同样,消费者线程并不一定每次只能处理一个数据。

在多缓冲区机制下,线程之间不必互相等待形成死锁,因而提高了效率。

多个缓冲区就好像使用一条传送带替代托架,传送带上一次可以放多个产品。

生产者在缓冲区尾加入数据,而消费者则在缓冲区头读取数据。

当缓冲区满的时候,缓冲区就上锁并等待消费者线程读取数据;每一个生产或消费动作使得传送带向前移动一个单位,因而,消费者线程读取数据的顺序和数据产生顺序是相同的。

可以引入一个count计数器来表示已经被使用的缓冲区数量。

用hNotEmptyEvent 和NotFullEvent 来同步生产者和消费者线程。

生产者消费者伪码_[线程同步]生产者消费者代码实现

生产者消费者伪码_[线程同步]生产者消费者代码实现

⽣产者消费者伪码_[线程同步]⽣产者消费者代码实现⽣产者消费者问题是⼀个著名的线程同步问题,该问题描述如下:有⼀个⽣产者在⽣产产品,这些产品将提供给若⼲个消费者去消费,为了使⽣产者和消费者能并发执⾏,在两者之间设置⼀个具有多个缓冲区的缓冲池,⽣产者将它⽣产的产品放⼊⼀个缓冲区中,消费者可以从缓冲区中取⾛产品进⾏消费,显然⽣产者和消费者之间必须保持同步,即不允许消费者到⼀个空的缓冲区中取产品,也不允许⽣产者向⼀个已经放⼊产品的缓冲区中再次投放产品。

⾸先来简化问题,先假设⽣产者和消费者都只有⼀个,且缓冲区也只有⼀个。

这样情况就简便多了。

1. 从缓冲区取出产品和向缓冲区投放产品必须是互斥进⾏的。

可以⽤关键段和互斥量来完成。

2. ⽣产者要等待缓冲区为空,这样才可以投放产品,消费者要等待缓冲区不为空,这样才可以取出产品进⾏消费。

并且由于有两个等待过程,所以要⽤两个事件或信号量来控制。

#include#include#includeCRITICAL_SECTION g_csThreadCode;HANDLE g_EventBuffFull;HANDLE g_EventBuffEmpty;int g_buffer;const int THREAD_NUM = 2;const int product_num = 100;unsigned int __stdcall producer_thread(void *param){for (int i = 0; i < product_num; i++){WaitForSingleObject(g_EventBuffEmpty, INFINITE);EnterCriticalSection(&g_csThreadCode);g_buffer = i;printf("⽣产者在缓冲区中放置⼀个产品,编号%d\n", g_buffer);LeaveCriticalSection(&g_csThreadCode);SetEvent(g_EventBuffFull);}return 0;}unsigned int __stdcall consumer_thread(void *param){for (int i = 0; i < product_num; i++){WaitForSingleObject(g_EventBuffFull, INFINITE);EnterCriticalSection(&g_csThreadCode);printf("消费者取⾛%d产品\n", g_buffer);g_buffer = 0;LeaveCriticalSection(&g_csThreadCode);SetEvent(g_EventBuffEmpty);}Sleep(10);return 0;}int main(){InitializeCriticalSection(&g_csThreadCode);g_EventBuffEmpty = CreateEvent(NULL, false, true, NULL);g_EventBuffFull = CreateEvent(NULL, false, false, NULL);HANDLE handle[THREAD_NUM];handle[0] = (HANDLE)_beginthreadex(NULL, 0, producer_thread, NULL, 0, NULL); handle[1] = (HANDLE)_beginthreadex(NULL, 0, consumer_thread, NULL, 0, NULL); WaitForMultipleObjects(THREAD_NUM, handle, true, INFINITE);//销毁同步资源DeleteCriticalSection(&g_csThreadCode);CloseHandle(handle[0]);CloseHandle(handle[1]);CloseHandle(g_EventBuffFull);CloseHandle(g_EventBuffEmpty);return 0;}代码执⾏结果:可以看出⽣产者与消费者已经是有序的⼯作了。

例9-10-Linux编程基础-黑马程序员-清华大学出版社

例9-10-Linux编程基础-黑马程序员-清华大学出版社

案例10:生产者-消费者模型是线程同步中的一个经典案例。

假设有两个线程,这两个线程同时操作一个共享资源(一般称为汇聚),其中一个模拟生产者行为,生产共享资源,当容器存满时,生产者无法向其中放入产品;另一个线程模拟消费者行为,消费共享资源,当产品数量为0时,消费者无法获取产品,应阻塞等待。

显然,为防止数据混乱,每次只能由生产者、消费者中的一个,操作共享资源。

本案例要求使用程序实现简单的生产者-消费者模型(可假设容器无限大)。

案例实现如下:1#include <stdio.h>2#include <stdlib.h>3#include <unistd.h>4#include <pthread.h>5struct msg {6 struct msg *next;7 int num;8};9struct msg *head;10pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; //初始化条件变量11pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //初始化互斥锁12//消费者13void *consumer(void *p)14{15 struct msg *mp;16 for (;;) {17 pthread_mutex_lock(&lock); //加锁18 //若头结点为空,表明产品数量为0,消费者无法消费产品19 while (head == NULL) {20 pthread_cond_wait(&has_product, &lock); //阻塞等待并解锁21 }22 mp = head;23 head = mp->next; //模拟消费一个产品24 pthread_mutex_unlock(&lock);25 printf("-Consume ---%d\n", mp->num);26 free(mp);27 sleep(rand() % 5);28 }29}30//生产者31void *producer(void *p)32{33 struct msg *mp;34 while (1) {35 mp = malloc(sizeof(struct msg));36 mp->num = rand() % 1000 + 1; //模拟生产一个产品37 printf("-Produce ---%d\n", mp->num);38 pthread_mutex_lock(&lock); //加锁39 mp->next = head; //插入结点(添加产品)40 head = mp;41 pthread_mutex_unlock(&lock); //解锁42 pthread_cond_signal(&has_product); //唤醒等待在该条件变量上的一个线程43 sleep(rand() % 5);44 }45}46int main(int argc, char *argv[])47{48 pthread_t pid, cid;49 srand(time(NULL));50 //创建生产者、消费者线程51 pthread_create(&pid, NULL, producer, NULL);52 pthread_create(&cid, NULL, consumer, NULL);53 //回收线程54 pthread_join(pid, NULL);55 pthread_join(cid, NULL);56 return 0;57}。

计算机操作系统课程设计源代码《生产者---消费者问题源代码》

计算机操作系统课程设计源代码《生产者---消费者问题源代码》

《生产者---消费者问题源代码》#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");/*换行*/}。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

操作系统课程设计生产者-消费者问题附代码

操作系统课程设计生产者-消费者问题附代码

枣庄学院信息科学与工程学院课程设计任务书题目:生产者-消费者问题的实现姓名:学号:专业:计算机科学与技术课程:操作系统指导教师:刘彩霞职称:讲师完成时间: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。

操作系统实验报告1 linux初步认知和生产者消费者问题

操作系统实验报告1 linux初步认知和生产者消费者问题

hierarchy
CLONE_SIGHAND 子进程与父进程共享相同的信号处理(signal handler)表
CLONE_PTRACE 若父进程被 trace,子进程也被 trace
CLONE_VFORK 父进程被挂起,直至子进程释放虚拟内存资源
CLONE_VM
子进程与父进程运行于相同的内存空间
CLONE_PID
#define inc(k) if(k < BUFFER_SIZE) k = k+1;else k=0//实现对缓冲区操作的
自增函数
并定义了如下实现问题的函数模块:
int insert_item(buffer_item item)
//将生产的产品放入缓冲区
int remove_item(buffer_item *item) //从缓冲区内移走一个产品
子进程在创建时 PID 与父进程一致
CLONE_THREAD 子进程与父进程共享相同的线程群
具体的实例如下图所示:
<4>生产者消费者问题的实现: 信号量 mutex 提供对缓冲池访问的互斥要求并初始化为 1,信号量 empty 和 full 分别用
来表示空缓冲项和满缓冲项的个数,信号量 empty 初始化为 n,信号量 full 初始化为 0。
进程是父进程的复制品且子进程装入另一个新程序;在第四章的结尾介绍了 clone()创建 线程的功能,linux 并不区分进程还是线程,clone()被调用时,它被传递一组标记以决定 父任务与子任务之间发生多少共享任务的数据结构,继而又从网上了解了其他的一些方 面区别,并进行了实验 <4>有限缓冲问题是一个经典的同步问题,可以通过信号量来实现进程同步。其中信号量 mutex 提供对缓冲池访问的互斥要求并初始化为 1,信号量 empty 和 full 分别用来表示空缓 冲项和满缓冲项的个数,信号量 empty 初始化为 n,信号量 full 初始化为 0

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

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

操作系统课程设计实验报告实验名称: 生产者消费者问题姓名/学号:一、实验目的以生产者和消费者问题为例, 学习Linux和Windows下进程通信、同步机制的具体实现方法, 主要是信号量和共享内存。

熟悉相关系统API的用法。

二、实验内容使用共享内存和信号量机制来实现多个生产者/消费者进程间的通信和同步。

要求在Linux和Windows下分别实现。

缓冲区大小为3, 初始为空。

2个生产者, 随机等待一段时间, 往缓冲区添加数据, 重复6次。

3个消费者, 重复4次。

三、实验环境Ubuntu 10.10 , GCC; Windows 7, VC 6.0;四、程序设计与实现1.Linux下:(1) 数据结构:a.共享内存定义为一个结构, 使得其数据成员更清晰且操作变得简单。

b.共享缓冲区采用循环队列的数据结构,由上面的结构struct buf { int start; int end; int info[BUF_NUM]; }维护。

其中start为队头指针, end为队尾指针, info为数据区域。

(2) 算法:a.大致由三个模块组成:i.主程序(main):ii.创建信号量、共享内存并进行初始化iii.创建生产者、消费者进程, 生产者执行pro_fun(), 消费者执行con_fun()iv.等待所有子进程的结束v.删除信号量、共享内存i.生产者进程(pro_fun):ii.通过key获得信号量、共享内存的ID, 将内存添加到自己的地址空间iii.P(empty), P(mutex), Add(data), V(mutex), V(full)iv.解除和共享内存的关联i.消费者进程(con_fun):ii.通过key获得信号量、共享内存的ID, 将内存添加到自己的地址空间iii.P(full), P(mutex), Add(data), V(mutex), V(empty)iv.解除和共享内存的关联循环队列部分:加入数据: info[end] = value; end = (end + 1) % 3;取出数据: temp = info[start]; info[start] = 0; (start = start + 1)%3; return temp;(3) 程序流程图:a.主函数:b.生产者进程:c.消费者进程和生产者类似4.Windows 下:(1) 数据结构:和Linux大致相同(2) 算法:a.创建的子进程调用正在执行的文件本身, 通过main函数的参数区分主进程和生产者、消费者进程。

操作系统_生产者与消费者问题的实现

操作系统_生产者与消费者问题的实现
shm_unlink("/shm"); /*删除共享内存区,程序中基本上保证了子进程先退出,因此父进程中无wait操作且这部操作放在父进程这里*/
//shmctl(shmid,IPC_RMID,&buf);
//del_sem(semid);
return 0;
}
/*生产者写5次后退出*/
void producer(key_t keyFull, key_t keyEmpty)
empty Write P1 : 2
empty Write P2 : 4
in = 0
Write : 5
full Write V1 : 0
full Write V2 : 0
full Read P2 : 0
out = 0
Read : 5
empty Read V1 : 4
empty Read V2 : 5
Write : 7
full Write V1 : 0
full Write V2 : 0
full Read P2 : 0
out = 2
Read : 7
empty Read V1 : 4
empty Read V2 : 5
Read Finish
p(empty); /*是否有空缓冲区,有则占有,无则被挂起,是原子操作*/
printf("empty Write P2 : %d\n", semctl(empty, 0, GETVAL, 0));
value_write++;
in = in++;
pData[in] = value_write;
in = in % 5;
printf("full Write V2 : %d\n", semctl(full, 0, GETVAL, 0));

实验三_生产者与消费者

实验三_生产者与消费者

实验三:生产者与消费者一、实验目的1.学习和掌握操作系统中进程之间的通信;2.理解和掌握使用信号量机制来是想进程之间的同步和互斥;3.学习使用创建文件对象,并利用文件映射对象来实现数据通信。

二、实验容•一个大小为6的缓冲区,初始为空,每个缓冲区能存放一个长度若为10个字符的字符串。

•2个生产者–随机等待一段时间,往缓冲区添加数据,–若缓冲区已满,等待消费者取走数据后再添加–重复12次•3个消费者–随机等待一段时间,从缓冲区读取数据–若缓冲区为空,等待生产者添加数据后再读取–重复8次说明:•显示每次添加和读取数据的时间及缓冲区的状态•生产者和消费者用进程模拟,缓冲区用共享存来实现三、实验环境1.Windows下:Windows8 ,Visual studio 20132.Linux下:Linux Ubuntu 4,gcc四、程序设计与实现1.Windows下:A.主要函数说明:(1)PROCESS_INFORMATIONStartClone(intnCloneID)功能:用来创建5个相同的进程,前两个为生产者,后三两个为消费者,赋予其不同的ID值,返回进程的信息。

(2)CreateSemaphore();功能:创建3个信号量:full,empty,mutex。

来互斥的访问缓冲区,实现通信。

(3)CreateFileMapping()功能:在当前运行的进程中创建文件映射对象,来模拟共享缓冲区MapViewOfFile()功能:在此文件映射上创建视图映射到当前应用程序的地址空间B.程序流程图实验代码如下:Windows://#include"stdafx.h"#include<stdio.h>#include<windows.h>#include<time.h>static HANDLE hMutexMapping=INVALID_HANDLE_VALUE;int num=0;HANDLE lpHandle[10];struct buf{int num;int read;int write;int buffer[5];};BOOL StartClone(){int i;BOOL bCreateOK;PROCESS_INFORMATION pi;TCHAR szFilename[MAX_PATH];GetModuleFileName(NULL,szFilename,MAX_PATH);TCHAR szCmdLine[MAX_PATH];for ( i = 0; i < 3; i++){sprintf(szCmdLine,"\"%s\" consumer %d",szFilename,i);STARTUPINFO si;ZeroMemory(reinterpret_cast<void*>(&si),sizeof(si)); si.cb=sizeof(si);bCreateOK=CreateProcess(szFilename,szCmdLine,NULL,NULL,FALSE,CREATE_DEFAULT_ERROR_MODE,NULL,NULL,&si,&pi);if (!bCreateOK){return false;lpHandle[num]=pi.hProcess;num++;}for ( i = 0; i < 2; i++){sprintf(szCmdLine,"\"%s\" productor %d",szFilename,i);STARTUPINFO si;ZeroMemory(reinterpret_cast<void *>(&si),sizeof(si)); si.cb=sizeof(si);bCreateOK=CreateProcess(szFilename,szCmdLine,NULL,NULL,FALSE,CREATE_DEFAULT_ERROR_MODE,NULL,NULL,&si,&pi);if (!bCreateOK)return false;}lpHandle[num]=pi.hProcess;num++;}return true;}void Parent(){printf("Creating the child process and waited child process to quit.\n");hMutexMapping=CreateMutex(NULL,true,"mutex");HANDLE hMapping=CreateFileMapping(NULL,NULL,PAGE_READWRITE,0,sizeof(LONG),"map");if (hMapping!=INVALID_HANDLE_VALUE){LPVOID pData=MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);if (pData!=NULL){ZeroMemory(pData,sizeof(LONG));}struct buf *pnData=reinterpret_cast<struct buf*>(pData);pnData->read=0;pnData->write=0;pnData->num=0;memset(pnData->buffer,0,sizeof(pnData->buffer)); UnmapViewOfFile(pData);}CreateSemaphore(NULL,3,3,"EMPTY");CreateSemaphore(NULL,0,3,"FULL");BOOL bCreateOK=StartClone();if (!bCreateOK){//printf("Create child process failed.\n");}else{//printf("Create child process success.\n");}ReleaseMutex(hMutexMapping);}void Productor(int n){int j;printf("Productor is running.\n");hMutexMapping=OpenMutex(MUTEX_ALL_ACCESS,true,"mutex");HANDLE hMapping=OpenFileMapping(FILE_MAP_ALL_ACCESS,NULL,"map");if (hMapping==INVALID_HANDLE_VALUE){printf("error\n");}HANDLE semEmpty =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"EMPTY");HANDLE semFull =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"FULL");for (int i = 0; i < 6; i++){WaitForSingleObject(semEmpty, INFINITE);SYSTEMTIME st;GetSystemTime(&st);srand((unsigned)time(0));Sleep(rand()/6);WaitForSingleObject(hMutexMapping,INFINITE);LPVOID pFile=MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);if (pFile!=NULL){struct buf *pnData=reinterpret_cast<struct buf *>(pFile);pnData->buffer[pnData->write]=1;pnData->write=(pnData->write+1)%3;pnData->num++;printf("%02d:%02d:%02d 生产者[%d]生产成功缓冲区中剩余%d个 ",st.wHour,st.wMinute,st.wSecond,n,pnData->num);for (j = 0; j < 3; j++){printf("%d ",pnData->buffer[j]);}printf("\n");}UnmapViewOfFile(pFile);pFile=NULL;ReleaseSemaphore(semFull, 1, NULL);ReleaseMutex(hMutexMapping);}printf("生产者[%d]生产完毕\n",n);}void Consumer(int n){int j;printf("Consumer is running.\n");hMutexMapping=OpenMutex(MUTEX_ALL_ACCESS,true,"mutex");HANDLE hMapping=OpenFileMapping(FILE_MAP_ALL_ACCESS,NULL,"map");if (hMapping==INVALID_HANDLE_VALUE){printf("error\n");}HANDLE semEmpty =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"EMPTY");HANDLE semFull =OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"FULL");for (int i = 0; i < 4; i++){WaitForSingleObject(semFull, INFINITE);SYSTEMTIME st;GetSystemTime(&st);srand((unsigned)time(0));Sleep(rand()/6);WaitForSingleObject(hMutexMapping,INFINITE);LPVOID pFile=MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);if (pFile!=NULL){struct buf *pnData=reinterpret_cast<struct buf *>(pFile);pnData->buffer[pnData->read]=0;pnData->read=(pnData->read+1)%3;pnData->num--;printf("%02d:%02d:%02d 消费者[%d]消费成功缓冲区中剩余%d个 ",st.wHour,st.wMinute,st.wSecond,n,pnData->num);for (j = 0; j < 3; j++){printf("%d ",pnData->buffer[j]);}printf("\n");}UnmapViewOfFile(pFile);pFile=NULL;ReleaseSemaphore(semEmpty,1,NULL);ReleaseMutex(hMutexMapping);}printf("消费者[%d]消费完毕\n",n);}int main(int argc,char **argv){if (argc>1&&strcmp(argv[1],"productor")==0){Productor(atoi(argv[2]));}else if (argc>1&&strcmp(argv[1],"consumer")==0){Consumer(atoi(argv[2]));}else{Parent();WaitForMultipleObjects(num,lpHandle,true,INFINITE); }return 0;}Linux下代码://随机等待一段时间int ran=random()%5;sleep(ran);}}Windows运行截图:Linux下截图:。

实习5生产者-消费者问题实现

实习5生产者-消费者问题实现
模拟操作系统中进程同步和互斥。
一、实习内容
熟悉临界资源、信号量及PV操作的定义与物理意义了解进程通信的方法掌握进程互斥与进程同步的相关知识掌握用信号量机制解决进程之间的同步与互斥问题实现生产者-消费者问题,深刻理解进程同步问题
二、实习目的
在Linux操作系统下用C实现经典同步问题:生产者—消费者,具体要求如下: (1)一个大小为10的缓冲区,初始状态为空。 (2)2个生产者,随机等待一段时间,往缓冲区中添加数据,若缓冲区已满,等待消费者取走数据之后再添加,重复10次。 (3)2个消费者,随机等待一段时间,从缓冲区中读取数据,若缓冲区为空,等待生产者添加数据之后再读取,重复10次。
管道通信系统 向管道提供输入的发送进程,以字符流方式将大量的数据送入管道,而接收进程从管道中接收数据。由于发送进程和接收进程是利用管道进行通信的,故称为管道通信。 为了协调发送和接收双方的通信,管道通信机制必须提供以下3方面的协调功能。 (1)互斥 当一个进程正在对pipe文件进行读或写操作时,另一个进程必须等待。 (2)同步 当写进程把一定数量的数据写入pipe文件后,便阻塞等待,直到读进程取走数据后,再把写进程唤醒。 (3)确认对方是否存在 只有确定对方已存在时,才能进行管道通信,否则会造成因对方不存在而无限制地等待。
在这个问题当中,我们采用信号量机制进行进程之间的通信,设置两个信号量,空的信号量和满的信号量。 在Linux系统中,一个或多个信号量构成一个信号量集合。使用信号量机制可以实现进程之间的同步和互斥,允许并发进程一次对一组信号量进行相同或不同的操作。每个P、V操作不限于减1或加1,而是可以加减任何整数。在进程终止时,系统可根据需要自动消除所有被进程操作过的信号量的影响 1.缓冲区采用循环队列表示,利用头、尾指针来存放、读取数据,以及判断队列是否为空。缓冲区中数组大小为10; 2.利用随机函数rand()得到A~Z的一个随机字符,作为生产者每次生产的数据,存放到缓冲区中;

生产者消费者pv例题

生产者消费者pv例题

生产者消费者pv例题生产者消费者问题是一个经典的并发编程问题,主要涉及到多个线程之间的同步和通信。

这个问题可以分为两部分:生产者和消费者。

生产者负责生成一定量的数据放到缓冲区,而消费者则从缓冲区中取出数据。

为了防止缓冲区溢出和被耗尽,需要使用到信号量等机制来进行同步。

以下是一个简单的生产者消费者问题的例子,用到了PV操作来控制:```c#include <stdio.h>#include <pthread.h>#include <stdlib.h>#define BUFFER_SIZE 100int buffer[BUFFER_SIZE];int in = 0, out = 0;pthread_mutex_t mutex; //互斥锁pthread_cond_t cond_empty, cond_full; //条件变量,分别表示缓冲区空和缓冲区满void *producer(void *arg) {int item;while (1) {item = produce_item(); //生产数据pthread_mutex_lock(&mutex);while ((in + 1) % BUFFER_SIZE == out) { //缓冲区满,等待消费者消费pthread_cond_wait(&cond_empty, &mutex);}buffer[in] = item;in = (in + 1) % BUFFER_SIZE; //入队printf("Producer produced item: %d\n", item);pthread_cond_signal(&cond_full); //唤醒消费者线程,告诉缓冲区有新数据可消费pthread_mutex_unlock(&mutex);}}void *consumer(void *arg) {while (1) {pthread_mutex_lock(&mutex);while (in == out) { //缓冲区空,等待生产者生产数据pthread_cond_wait(&cond_full, &mutex);}int item = buffer[out];out = (out + 1) % BUFFER_SIZE; //出队printf("Consumer consumed item: %d\n", item);pthread_cond_signal(&cond_empty); //唤醒生产者线程,告诉缓冲区有空间可放新数据pthread_mutex_unlock(&mutex);}}```。

操作系统实验报告 经典的生产者—消费者问题

操作系统实验报告  经典的生产者—消费者问题

实验二经典的生产者—消费者问题一、目的实现对经典的生产者—消费者问题的模拟,以便更好的理解经典进程同步问题。

二、实验内容及要求编制生产者—消费者算法,模拟一个生产者、一个消费者,共享一个缓冲池的情形。

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("缓冲区被占用,请等待。

生产者消费者问题/银行家算法

生产者消费者问题/银行家算法

操作系统课程设计题目一:实现生产者消费者问题题目二:银行家算法的实现一、实验题目解决生产者-消费者问题二、设计内容有界缓冲区内设有10个存储单元,放入/取出的数据项设定为1~10这10个整形数。

要求每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容、当前指针位置和生产者/消费者标识符三、开发环境LINUX环境,工具为VI编辑器。

四、分析设计(一)实验原理使用的生产者和消费者模型具有如下特点:(1)本实验的多个缓冲区不是环形循环的,也不要求按顺序访问。

生产者可以把产品放到目前某一个空缓冲区中。

(2)消费者只消费指定生产者的产品。

(3)在测试用例文件中指定了所有的生产和消费的需求,只有当共享缓冲区的数据满足了所有关于它的消费需求后,此共享缓冲区才可以作为空闲空间允许新的生产者使用。

(4)本实验在为生产者分配缓冲区时各生产者间必须互斥,此后各个生产者的具体生产活动可以并发。

而消费者之间只有在对同一产品进行消费时才需要互斥,同时它们在消费过程结束时需要判断该消费对象是否已经消费完毕并清除该产品。

Windows 用来实现同步和互斥的实体。

在Windows 中,常见的同步对象有:信号量(Semaphore)、互斥量(Mutex)、临界段(CriticalSection)和事件(Event)等。

本程序中用到了前三个。

使用这些对象都分为三个步骤,一是创建或者初始化:接着请求该同步对象,随即进入临界区,这一步对应于互斥量的上锁;最后释放该同步对象,这对应于互斥量的解锁。

这些同步对象在一个线程中创建,在其他线程中都可以使用,从而实现同步互斥。

当然,在进程间使用这些同步对象实现同步的方法是类似的。

1.用锁操作原语实现互斥为解决进程互斥进人临界区的问题,可为每类临界区设置一把锁,该锁有打开和关闭两种状态,进程执行临界区程序的操作按下列步骤进行:①关锁。

先检查锁的状态,如为关闭状态,则等待其打开;如已打开了,则将其关闭,继续执行步骤②的操作。

生产者和消费者代码

生产者和消费者代码

#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; //请求个数};//全局变量的定义//临界区对象的声明,用于管理缓冲区的互斥访问;int Buffer_Critical[MAX_BUFFER_NUM]; //缓冲区声明,用于存放产品;ThreadInfo Thread_Info[MAX_THREAD_NUM]; //线程信息数组;HANDLE h_Thread[MAX_THREAD_NUM]; //用于存储每个线程句柄的数组;HANDLE empty_semaphore; //一个信号量;HANDLE h_mutex; //一个互斥量;HANDLE h_Semaphore[MAX_THREAD_NUM]; //生产者允许消费者开始消费的信号量;CRITICAL_SECTION PC_Critical[MAX_BUFFER_NUM];DWORD n_Thread = 0; //实际的线程的数目;DWORD n_Buffer_or_Critical; //实际的缓冲区或者临界区的数目;//生产消费及辅助函数的声明void Produce(void *p);void Consume(void *p);bool IfInOtherRequest(int);int FindProducePositon();int FindBufferPosition(int);int main(int argc, char **argv){//声明所需变量;DWORD wait_for_all;ifstream inFile;if (argc!=2) {printf("Usage:%s <File>\n",argv[0]);return 1;}//初始化缓冲区;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(argv[1]);//从文件中获得实际的缓冲区的数目,即测试文件第一行的信息;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(" \nthread%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++) {char lp[]="semaphore_for_produce_";int temp =j;while(temp){char c = (char)(temp%10);strcat(lp,&c);temp/=10;}h_Semaphore[j+1]=CreateSemaphore(NULL,0,n_Thread,lp);}//创建生产者和消费者线程;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);//互斥访问下一个可用于生产的空临界区,实现写写互斥;wait_for_mutex = WaitForSingleObject(h_mutex,-1);//确认有空缓冲区可供生产,同时将空位置数empty减1;用于生产者和消费者的同步;//若没有则一直等待,直到消费者进程释放资源为止;wait_for_semaphore = WaitForSingleObject(empty_semaphore,-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\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; //-1标记缓冲区为空;printf("Consumer %2d finish consuming %2d:\n ",m_serial,m_thread_request[i]);printf(" position[ %2d ]:%3d \n\n" ,BufferPos,Buffer_Critical[BufferPos]);ReleaseSemaphore(empty_semaphore,1,NULL);}else {printf("Consumer %2d finish consuming product %2d\n\n ",m_serial,m_thread_request[i]);}//离开临界区LeaveCriticalSection(&PC_Critical[BufferPos]);}}。

生产者消费者问题实现

生产者消费者问题实现

生产者消费者问题实现班级姓名学号一.实验目的1.熟悉临界资源、信号量及PV操作的定义与物理意义2.了解线程通信的方法3.掌握线程互斥与同步的相关知识4.掌握用信号量机制解决线程之间的同步与互斥问题5.实现生产者-消费者问题,深刻理解线程同步问题二、实验的硬件、软件平台硬件:计算机软件:操作系统win10应用软件:Dev C++三、实验原理生产者-消费者问题是一个经典的线程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。

在同一个线程地址空间内执行的两个线程。

生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。

消费者线程从缓冲区中获得物品,然后释放缓冲区。

当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。

当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。

多个生产/消费者在有界缓冲上操作。

它利用N个字节的共享内存作为有界循环缓冲区,利用写一字符模拟放一个产品,利用读一字符模拟消费一个产品。

当缓冲区空时消费者应阻塞睡眠,而当缓冲区满时生产者应当阻塞睡眠。

一旦缓冲区中有空单元,生产者线程就向空单元中入写字符,并报告写的内容和位置。

一旦缓冲区中有未读过的字符,消费者线程就从该单元中读出字符,并报告读取位置。

生产者不能向同一单元中连续写两次以上相同的字符,消费者也不能从同一单元中连续读两次以上相同的字符。

在进行多线程编程时,由于资源共享和进程间合作而造成进程间相互制约,难免还要碰到两个问题,那就线程间的互斥与同步:线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。

线程互斥是指对于共享的进程系统资源,在各单个线程访问时的排它性。

当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。

操作系统课程设计-管程的实现(生产者消费者问题)

操作系统课程设计-管程的实现(生产者消费者问题)

操作系统课程设计2、管程的实现(生产者消费者问题)1.设计背景:管程是一种高级抽象数据类型,它支持在它的函数中隐含互斥操作。

结合条件变量和其他一些低级通信原语,管程可以解决许多仅用低级原语不能解决的同步问题。

例如,本实验中利用管程提供一个不会发生死锁的生产者消费者问题就是利用管程的很好的例子。

管程封装了并发进程或线程要互斥执行的函数。

为了让这些并发进程或线程在管程内互斥的执行,管程的实现必须隐含的具有锁或二值信号量。

如果没有条件变量,管程就不会有很有用,条件变量提供了一种对管程内并发协作进程的同步机制。

条件变量代表了管程中一些并发进程或线程可能要等待的条件。

一个条件变量管理着管程内的一个等待队列。

如果管程内某个进程或线程发现其执行条件为假,则该进程或线程就会被条件变量挂入管程内等待该条件的队列。

如果管程内另外的进程或线程满足了这个条件,则它会通过条件变量再次唤醒等待该条件的进程或线程,从而避免了死锁的产生。

所以,一个条件变量C应具有两种操作 C.wait()和C.signal()。

当管程内同时出现唤醒者和被唤醒者时,由于要求管程内的进程或线程必须互斥执行,因此就出现了两种样式的条件变量:Mesa Style(signal-and-continue): 唤醒者进程或线程继续执行,被唤醒者进程或线程等到唤醒者进程或线程阻塞或离开管程后再执行。

Hoare Style(signal-and-wait): 被唤醒者进程或线程立即执行,唤醒者进程或线程阻塞,直道被唤醒者阻塞或离开管程后再执行。

我们实验所做的就是在原来mesa样式的基础上进行Hoare样式的改进;这种样式也是我们实验中需要实现的样式。

2.设计目标验证并分析Nachos中Bridge管程是否能够正确的解决单行桥双向过桥问题。

定义和实现Hoare样式的条件变量Condition_H类利用Hoare样式的条件变量Condition_H,实现Ring类中定义的各个方法,使用Ring管程解决生产者/消费者问题。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
pthread_join(C,NULL);
pthread_join(D,NULL);
pthread_join(E,NULL);
return 0;
}
switch (phi){
case 'A':
left = 5;
right = 1;
break;
case 'B':
left = 1;
right = 2;
break;
case 'C':
left = 2;
right = 3;
break;
case 'D':
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
//筷子作为mutex
pthread_mutex_t chopstick[6] ;
void *eat_think(void *arg)
{
char phi = *(char *)arg;
int left,right; //左右筷子的编号
printf("Philosopher %c is eating.\n",phi);
usleep(3); //吃饭
pthread_mutex_unlock(&chopstick[left]); //放下左手的筷子
printf("Philosopher %c release chopstick %d\n", phi, left);
printf("Philosopher %c fetches chopstick %d\n", phi, left);
if (pthread_mutex_trylock(&chopstick[right]) == EBUSY){ //拿起右手的筷子
pthread_mutex_unlock(&chopstick[left]); //如果右边筷子被拿走放下左手的筷子
int i;
for (i = 0; i < 5; i++)
pthread_mutex_init(&chopstick[i],NULL);
pthread_create(&A,NULL, eat_think, "A");
pthread_create(&B,NULL, eat_think, "B");
left = 3;
right = 4;
break;
case 'E':
left = 4;
right = 5;
break;
}sleep(3); //思考
pthread_mutex_lock(&chopstick[left]); //拿起左手的筷子
continue;
}
//pthread_mutex_lock(&chopstick[right]); //拿起右手的筷子,如果想观察死锁,把上一句if注释掉,再把这一句的注释去掉
printf("Philosopher %c fetches chopstick %d\n", phi, right);
pthread_mutex_unlock(&chopstick[right]); //放下右手的筷子
printf("Philosopher %c release chopstick %d\n", phi, right);
}
}
int main(){
pthread_t A,B,C,D,E; //5个哲学家
pthread_create(&C,NULL, eat_think, "C");
pthread_create(&D,NULL, eat_think, "D");
pthread_create(&E,NULL, eat_think, "E");
pthread_join(A,NULL);
pthread_join(B,NULL);
相关文档
最新文档