实验二生产者和消费者

时间:2024.2.19

1.1 实验目标

掌握操作系统对进程管理的同步和互斥问题,以经典同步问题“生产者和消费者”为例,运用所学C语言知识,编写该问题的模拟运行环境。

1.2 实验环境

教学机房,C语言程序平台。

1.3 实验内容及步骤

1.了解经典同步问题“生产者和消费者”

生产者与消费者可以通过一个环形缓冲池联系起来,环形缓冲池由几个大小相等的缓冲块组成,每个缓冲块容纳一个产品。每个生产者可不断地每次往缓冲池中送一个生产产品,而每个消费者则可不断地每次从缓冲池中取出一个产品。指针i和指针j分别指出当前的第一个空缓冲块和第一个满缓冲块。

2.分析和理解

(1)既存在合作同步问题,也存在临界区互斥问题

合作同步:当缓冲池全满时,表示供过于求,生产者必须等待,同时唤醒消费者;当缓冲池全空时,表示供不应求,消费者应等待,同时唤醒生产者。

互斥:缓冲池显然是临界资源,所在生产者与消费都要使用它,而且都要改变它的状态。

(2)基于环形缓冲区的生产者与消费者关系形式描述:

公用信号量mutex:初值为1,用于实现临界区互斥

生产者私用信号量empty:初值为n,指示空缓冲块数目

消费者私用信号量full:初值为0,指示满缓冲块数目

整型量i和j初值为0,i指示首空缓冲块序号,j指示首满缓冲块序号

(3)PV原语

var mutex,empty,full:semaphore;

i,j:integer;buffer:array[0...n-1] of item;

i:=j:=1;

Procedure producer;

begin

while true do

begin

produce a product;

P(empty);

P(mutex);

buffer(i):=product;

i:=(i+1) mod n;

V(mutex);

V(full);

end;

end;

Procedure consumer;

begin

P(full);

P(mutex);

goods:=buffer(j);

j:=(j+1) mod n;

V(mutex);

V(empty);

consume a product;

end;

end;

3.用C语言编程搭建“生产者和消费者”经典进程通信问题的环境。要求程序运行时,按任意键停止,显示当前系统的各个参数的值。提交实验报告,以及相关程序列表。打包成附件上传。

#include

#include

#include

#define P(S) WaitForSingleObject(S,INFINITE)//定义Windows下的P操作

#define V(S) ReleaseSemaphore(S,1,NULL)//定义Windows下的V操作

#define rate 1000

#define CONSUMER_NUM 10 /*消费者个数*/

#define PRODUCER_NUM 10 /*生产者个数*/

#define BUFFER_NUM 4 /*缓冲区个数*/

typedef HANDLE Semaphore; //信号量的Windows原型

char *thing[10]= {"物品1","物品2","物品3","物品4","物品5",

"物品6","物品7","物品8","物品9","物品10"};

struct Buffer

{

int product[BUFFER_NUM]; //缓冲区

int start,end; //两个指针

}g_buf; Semaphore g_semBuffer,g_semProduct,g_mutex;

//消费者线程

DWORD WINAPI Consumer(LPVOID para)

{

int i=*(int *)para; //i表示第i个消费者

int ptr,j; //待消费的内容的指针

Sleep(100);

while(1)

{

P(g_semProduct); //有产品,先锁住缓冲区

P(g_mutex); //记录消费的物品

ptr=g_buf.start; //再移动缓冲区指针

g_buf.start=(g_buf.start+1)%BUFFER_NUM;

V(g_mutex); //让其他消费者或生产者使用 g_buf

printf("消费者%d:消费了buf[%d]里的=%s\n",i,ptr,thing[g_buf.product[ptr]]);

Sleep(rate*rand()%10+110);

//消费完毕,并释放一个缓冲

V(g_semBuffer);

if(j++>30)break;

}

getchar();

return 0;

}

// 生产者线程

DWORD WINAPI Producer(LPVOID para)

{

int i=*(int *)para-CONSUMER_NUM;

int ptr;

int data; //产品

Sleep(100);

while(1)

{

Sleep(rate*rand()%10+110);

data=rand()%10;

//等待存放空间

P(g_semBuffer); //有地方,先锁住缓冲区

P(g_mutex);

// 记录消费的物品

ptr=g_buf.end;

// 再移动缓冲区指针

g_buf.end=(g_buf.end+1)%BUFFER_NUM;

//让其他消费者或生产者使用 g_buf

V(g_mutex);

printf("生产者%d:在buf[%d]里放入了%s\n",i,ptr,thing[data]);

g_buf.product[ptr]=data;

Sleep(rate/2*rand()%10+110);

//放好了完毕,释放一个产品

V(g_semProduct);

}

return 0;

}

int main(int argc,char *argv[])

{ //线程技术,前面为消费者线程,后面为生产者线程

HANDLE hThread[CONSUMER_NUM+PRODUCER_NUM]; //线程计数

//srand(time());

DWORD tid;

int i=0;

// 初始化信号量

g_mutex=CreateSemaphore(NULL,BUFFER_NUM,BUFFER_NUM,"mutexOfConsumerAndProducer");

g_semBuffer=CreateSemaphore(NULL,BUFFER_NUM,BUFFER_NUM,"BufferSemaphone");

g_semProduct=CreateSemaphore(NULL,0,BUFFER_NUM,"ProductSemaphone");

if(!g_semBuffer||!g_semProduct||!g_mutex)

{

printf("Create Semaphone Error!\n");

return -1;

}

int totalThreads=CONSUMER_NUM+PRODUCER_NUM;

// 开启消费者线程

for(i=0;i

{

hThread[i]=CreateThread(NULL,0,Consumer,&i,0,&tid);

if(hThread[i])WaitForSingleObject(hThread[i],10);

}

//开启 生产者线程

for(;i

{

hThread[i]=CreateThread(NULL,0,Producer,&i,0,&tid);

if(hThread[i])WaitForSingleObject(hThread[i],10);

}

//生产者和消费者的执行

WaitForMultipleObjects(totalThreads,hThread,TRUE,INFINITE);

return 0;

}

1.4 实验思考题

1.思考在“生产者和消费者”经典同步问题中,两个P操作是否可以互换位置,以及两个V操作是否可以互换位置。

在生产者-消费者问题中,如果将两个P操作,即P(full)和P(mutex)互换位置,或者P(empty)和P(mutex)互换位置,都可能引起死锁。考虑系统中缓冲区全满时,若以生产者进程先执行了P(mutex)操作并获得成功,当再执行P(empty)操作时,他将因失败而进入阻塞状态,它期待消费者执行V(empty)来唤醒自己。在此之前,它不可能执行V(mutex)操作,从而使企图通过P(mutex)进入自己的临界区的其他生产者和所有消费者进程全部进入阻塞状态,从而引起系统死锁。类似地,消费者进程若先执行P(mutex),后执行P(full),同样可能造成死锁。

V(full)和V(mutex)互换位置,或者V(empty)和V(mutex)互换位置,则不会引起死锁,其影响只是使临界资源的释放略微推迟一些。

2.思考在“哲学家就餐”经典同步问题中,如何修改程序,可以保证不会发生死锁现象。

(1)至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用毕是能释放出他用过的两只筷子,从而使更多的哲学家能够进餐。

(2)仅当哲学家的左、右两只筷子均可使用时,才允许他拿起筷子进餐。

(3)规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子,而偶数号哲学家则相反。按此规定,将是1、2号哲学家竞争1号筷子;3、4号哲学家竞争3号筷子。即五位哲学家都先竞争奇数号筷子,获得后,再去竞争偶数号筷子,最后总会有一位哲学家能获得两只筷子而进餐。

3.思考在“读者与写者”经典同步问题中,如何修改程序,变为“写者优先”的算法。

(写者优先算法)

Var rmutex,wmutex,mutex,s:semaphore=1,1,1,1;

Writecount:integer:=0;

Reader:begin

Repeat

Wait(s);

Wait(rmutex);

If readcount=0 then wait(wmutex);

Readcount:readcount+1;

Signal(rmutex);

Signal(s);

Perform read operation;

Wait(rmutex);

Readcount:=readcount:=readcount-1;

If readcount=0 then signal(wmutex);

Signal(rmutex);

Until false;

End

Writer:begin

Repeat

Wait(mutex);

If writecount=0 then wait(s);

Writecount:writecount+1;

Signal(mutex);

Wait(wmutex);

Perform write operatin;

Signal(wmutex);

Wait(mutex);

Writecount=0 then signal(s);

Signal(mutex);

Until false;

end

4.分析以下进程运行环境中出现的同步和互斥现象,列出相应的变量和参数。

理发店理有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子。如果没有顾客,理发师便在理发椅上睡觉。一个顾客到来时,它必须叫醒理发师。如果理发师正在理发时又有顾客来到,则如果有空椅子可坐,就坐下来等待,否则就离开。

理发师是顾客争用资源,用信号量barbers表示,初值为0;除此之外,顾客还要争用n张椅子,信号量customers表示等候理发的顾客,初值为0;最后设置信号量mutex用于这两个活动对资源barbers/customers的互斥,初值为1.另外还需要使用一个变量waiter,用于记录等候的顾客的数量。


第二篇:实验二 生产者与消费者实验报告


实验二 进程的互斥与同步(生产者与消费者问题)实验报告 实验目的:利用Windows提供的API函数,用VISUALC++ 6.0编写程序,解决生产者与消费者问题,实现进程的互斥与同步

实验内容和步骤:本实验设计在同一个进程地址空间内执行的七个线程。三个生产者线程四个消费者线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。生产者线程生产物品时,若无空缓冲区可用,生产者线程必须等待消费者线程释放出一个空缓冲区;消费者线程消费物品时,若无满的缓冲区,消费者线程将被阻塞,直到新的物品被生产出来。

本实验中三个生产者线程的区别只在生产产品的时间不同,分别为:1秒、2秒、3秒;四个消费者线程的区别也只在消费产品的时间不同,分别为:0.5秒、1秒、1.5秒、2秒。它们使用二个不同的缓冲区。需要使用如下信号量:

一个互斥信号量,用以阻止生产者线程和消费者线程同时操作缓冲区列表;

一个信号量,用于当缓冲区满时让生产者线程等待;

一个信号量,用于当缓冲区空时让消费者线程等待;

接下来利用VC++6.0编写一段程序,模拟生产者和消费者线程,实现进程的互斥与同步。程序结果通过DOS下窗口输出,使生产者和消费者自动生产和消费产品,通过按回车键来使程序退出。

主程序结构:

1、 此程序要用到的头文件,有3个:windows.h、iostream、d_random.h(用于产生随机数模拟产品)

2、 全局变量的定义,分别有:h_Mutex(互斥信号)、bufferFullSemaphore(当缓冲区满时生产者等待信号量)、bufferEmptySemaphore(当缓冲区空时消费者等待信号量)、BUFFER_SIZE(缓冲区长度)、buffer[](数组模拟缓冲区循环队列)、in(用与追踪产品进缓冲区时的缓冲区数组下标)、out(用与追踪产品出缓冲区时的缓冲区数组下标)、rndNum(用于产生随机数)、producerID[](生产者线程的标识符)、consumerID[](消费者线程的标识符)、control(控制生产者消费者线程的循环的标志)

3、 生产者函数,3个生产者的函数名字分别为:producer1、producer2、producer3,其中区别只在于函数中的Sleep()的参数不同,分别为:1000、2000、3000。此函数用于执行生产者线程时所要进行的操作,本程序模拟生产者生产一个10000到99999的随机数做产品,并输出生产出的这个数字,并输出产品生产后缓冲区的储存情况

4、 消费者函数,4个消费者的函数名字分别为:consumer1、consumer2、consumer3、consumer4,其中区别只在于函数中的Sleep()的参数不同,分别为:500、1000、1500、2000。此函数用于执行消费者线程时所要进行的操作,本程序模拟消费者消费一个缓冲区已经存在的数字,消费完后使此缓冲区的数字变0来表示该区无产品,并输出产品生产后缓冲区的储存情况

5、 主函数部分,对全局变量定义的信号量赋值,创建3个生产者线程和4个消费者线程,实验当按回车键的时候程序退出(使控制变量control为false)

实验中所遇到的问题及解决办法:

1、 生产者消费者函数问题。

由于3个生产者函数之间和4个消费者函数之间的区别只是Sleep()这个函数的参 数不同,于是一开始我编了一个生产者函数和一个消费者函数,它们都接受一个参数sleepTime用于确定Sleep()函数中的参数。但在创建线程的函数CreateThread()中,生产者函数和消费者函数要做为这个函数的第三个参数传进来,而这个创建线程的函数的参数

定义来看,第三个传递进来的函数不能接受非void *类型的参数,于是该方案失败,考虑过把生产者和消费者创建成类,但还是失败了,最终解决办法是编写了3个生产者函数和4个消费者函数,导致代码加长。更有效的解决办法还请老师指导指导。

2、 程序结束问题。

一开始我想让程序自动结束,初步想法是定义一个变量追踪实际线程数目,再定义一 个常量为最大线程数目,当实际线程数目大于最大线程数目时程序结束(见我原程序注释掉了的变量及程序),此办法我运行后程序并不能如我想的结束,百思不得其解后我变把程序改成用回车键来结束了

更多相关推荐:
生产者与消费者实验报告

生产者和消费者实验报告实验目的1加深对进程概念的理解明确进程和程序的区别2进一步认识并发执行的实质3验证用信号量机制实现进程互斥的方法4验证用信号量机制实现进程同步的方法实验要求用c语言编程搭建生产者和消费者经...

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

实验报告五生产者和消费者问题姓名丛菲学号20xx0830205班级信息安全二班一实习内容1模拟操作系统中进程同步和互斥2实现生产者和消费者问题的算法实现二实习目的1熟悉临界资源信号量及PV操作的定义与物理意义2...

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

实验二经典的生产者消费者问题一目的实现对经典的生产者消费者问题的模拟以便更好的理解经典进程同步问题二实验内容及要求编制生产者消费者算法模拟一个生产者一个消费者共享一个缓冲池的情形1实现对经典的生产者消费者问题的...

《操作系统》实验报告 生产者——消费者

数学与信息技术学院南京晓庄学院操作系统实验报告指导老师专业班级学号姓名完成日期数学与信息技术学院1数学与信息技术学院一实验概述1实验目的深入了解掌握进程的同步互斥机制认识理解其调度过程并用于解决实际生产者消费者...

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

操作系统实验报告生产者和消费者的问题一实验目的1掌握基本的同步与互斥的算法理解基本的生产者与消费者的模型2学习使用Windows20xxXP中基本的同步对象掌握相关的API的使用方法3了解Windows20xx...

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

操作系统课程设计实验报告实验名称生产者消费者问题姓名学号一实验目的以生产者和消费者问题为例学习Linux和Windows下进程通信同步机制的具体实现方法主要是信号量和共享内存熟悉相关系统API的用法二实验内容使...

生产者消费者实验报告

实验二生产者与消费者进程实验报告实验目的利用Windows提供的API函数编写程序解决生产者与消费者问题实现进程的互斥与同步实验内容与步骤1进程的互斥与同步编写一段程序模拟生产者和消费者线程实现进程的互斥与同步...

生产者消费者实验

生产者消费者实验实验内容以生产者消费者模型为依据提供一个多线程生产者消费者实例用VC或java实现并具备以下功能1可改变缓冲区数目2可增加或减少线程数目3改变延迟时间4可增加或减少生产者消费者进程数目5可改变消...

实验8 多线程“生产者消费者”实验

南昌大学实验报告学生姓名王维学号6100212202专业班级网工121班实验类型验证综合设计创新实验日期514实验成绩一实验项目名称实验8多线程生产者消费者实验二实验目的生产者消费者问题是一个著名的同时性编程问...

实验二 生产者-消费者问题

实验二生产者消费者问题实验目的掌握进程同步和互斥算法掌握WIN32API中基本的同步对象使用WIN32API解决实际问题实验内容生产者消费者问题是一个经典的进程同步问题该问题最早由Dijkstra提出用以演示他...

消费心理学第一次实验报告

桂林电子科技大学信息科技学院消费心理学实验实验报告题目消费观及消费行为分析班级市场营销指导老师杨帆小组成员XXX1054110110XXX1054110114XXX1054110115XXX1054110116...

实验十一 波形发生电路实验报告

实验十一波形发生电路一实验目的1掌握波形发生电路的特点和分析方法2熟悉波形发生器设计方法二实验仪器1双踪示波器2数字万用表三实验要求1分析图111电路的工作原理定性画出V0和VC波形2若图111电路Rl0K计算...

生产者消费者实验报告(25篇)