操作系统课程设计用多进程同步方法解决生产者-消费者问题(1)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
操作系统课程设计
用多进程同步方法解决生产者-消费者问题
系别:计科系
专业: 计算机科学与技术
班级:04 级 4 班
学号:
姓名:苏德洪
时间:2006-7-7—2006-7-14
目录
一、题目: (3)
二、设计目的: ........................................................ 错误!未定义书签。
三、总体设计思想概述: ........................................ 错误!未定义书签。
四、说明:................................................................. 错误!未定义书签。
五、设计要求: ........................................................ 错误!未定义书签。
六、设计方案: ........................................................ 错误!未定义书签。
七、流程图: (5)
八、运行结果 (7)
九、源程序................................................................. 错误!未定义书签。
十、总结..................................................................... 错误!未定义书签。
十一、参考文献 .. (20)
一、题目:
用多进程同步方法解决生产者-消费者问题。
二、设计目的:
掌握信号量机制的过程。
掌握c语言编程。
通过研究Linux 的进程机制和信号量实现生产者消费者问题的并发控制。
三、总体设计思想概述:
1、生产者—消费者问题是一种同步问题的抽象描述。
2、计算机系统中的每个进程都可以消费或生产某类资源。
当系统中某一进程使用某一
资源时,可以看作是消耗,且该进程称为消费者。
3、而当某个进程释放资源时,则它就相当一个生产者。
四、说明:
有界缓冲区用数组表示。
五、设计要求:
1、每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容,当前
指针位置和生产者/消费者线程的标识符。
2、生产者和消费者各有两个以上。
3、多个生产者或多个消费者之间须有共享对缓冲区进行操作的函数代码。
六、设计方案:
通过一个有界缓冲区(用数组来实现,类似循环队列)把生产者和消费者联系起来。
假定生产者和消费者的优先级是相同的,只要缓冲区未满,生产者就可以生产产品并将产品送入缓冲区。
类似地,只要缓冲区未空,消费者就可以从缓冲区中去走产品并消费它。
应该禁止生产者向满的缓冲区送入产品,同时也应该禁止消费者从空的缓冲区中取出产品,这一机制有生产者线程和消费者线程之间的互斥关系来实现。
为解决生产者/消费者问题,应该设置两个资源信号量,其中一个表示空缓冲区的数目,用g_hFullSemaphore表示,其初始值为有界缓冲区的大小SIZE_OF_BUFFER;另一个表示缓冲区中产品的数目,用g_hEmptySemaphore表示,其初始值为0。
另外,由于有
界缓冲区是一个临界资源,必须互斥使用,所以还需要再设置一个互斥信号量g_hMutex,起初值为1。
在生产者/消费者问题中,信号量实现两种功能。
首先,它是生产产品和消费产品的计数器,计数器的初始值是可利用的资源数目(有界缓冲区的长度)。
其次,它是确保产品的生产者和消费者之间动作同步的同步器。
生产者要生产一个产品时,首先对资源信号量g_hFullSemaphore和互斥信号量g_hMutex进行P操作,申请资源。
如果可以通过的话,就生产一个产品,并把产品送入缓冲区。
然后对互斥信号量g_hMutex和资源信号量g_hEmptySemaphore进行V操作,释放资源。
消费者要消费一个产品时,首先对资源信号量g_hEmptySemaphore和互斥信号量g_hMutex进行P操作,申请资源。
如果可以通过的话,就从缓冲区取出一个产品并消费掉。
然后对互斥信号量g_hMutex和资源信号量g_hFullSemaphore进行V操作,释放资源。
如果缓冲区中已经没有可用资源,就把申请资源的进程添加到等待队列的队尾。
如果有一个资源被释放,在等待队列中的第一个进程被唤醒并取得这个资源的使用权。
七、流程图:
1、生产者
2、消费者
八、运行结果
1、截图一:
2、截图二:
3、截图三:
九、源程序
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
int o=0;
const unsigned short SIZE_OF_BUFFER = 20;//有界缓冲区长度
int g_buffer[SIZE_OF_BUFFER];//开辟缓冲区,用数组表示,可以看成是一个循环队列unsigned short ProductID = 0;//新生产出来的产品的产品号
unsigned short ConsumeID = 0;//被消耗的产品的产品号
unsigned short in = 0;//产品进缓冲区时的缓冲区下标,用于记录生产者的指针位置unsigned short out = 0;//产品出缓冲区时的缓冲区下标,用于记录消费者的指针位置
bool g_continue = 1;//控制程序运行:1表示继续运行,0表示停止运行
HANDLE g_hMutex;//线程间的互斥信号量
HANDLE g_hFullSemaphore;//资源信号量:缓冲区满
HANDLE g_hEmptySemaphore;//资源信号量:缓冲区空
DWORD WINAPI Producer(LPVOID);//生产者线程
DWORD WINAPI Consumer(LPVOID);//消费者线程
const unsigned short PRODUCERS_COUNT=3;//生产者的个数
const unsigned short CONSUMERS_COUNT=5;//消费者的个数
const unsigned short THREADS_COUNT=PRODUCERS_COUNT+CONSUMERS_COUNT;//总线程数HANDLE hThreads[PRODUCERS_COUNT];//各线程的handle
DWORD producerID[CONSUMERS_COUNT];//生产者线程的标识符
DWORD consumerID[THREADS_COUNT];//消费者线程的标识符
/*----------------------------生产一个产品开始------------------------------*/ //生产一个产品,输出其ID号
void Produce()
{
system("color 3e");
std::cout<<std::endl;
std::cerr<<" "<<"生产一个产品: "<<++ProductID;
std::cout<<std::endl;
}
/*----------------------------生产一个产品结束------------------------------*/
/*----------------------把新生产的产品放入缓冲区开始------------------------*/ //把新生产的产品放入缓冲区
void Append()
{
// std::cerr<<" "<<"把生产的产品送入缓冲区";
g_buffer[in]=ProductID;
in=(in+1)%SIZE_OF_BUFFER;
std::cerr<<std::endl;
std::cout<<" 缓冲区 "<<" 产品 "<<std::endl;
//新产品放入缓冲区后,输出缓冲区当前的状态
for(int i=0;i<SIZE_OF_BUFFER;++i)
{
if(i==in)
{
if(g_buffer[i]<10)
std::cout<<" ";
else
std::cout<<" ";
std::cout<<"生产者-->";//输出生产者的指针位置
// std::cout<<" ";
}
//输出缓冲区下标
if (i<10&&i!=in)
std::cout<<" "<<i<<" "<<g_buffer[i];
else if(i<10&&i==in)
std::cout<<" "<<i<<" "<<g_buffer[i];
else if(i>=10&&i!=in)
std::cout<<" "<<i<<" "<<g_buffer[i];
else if(i>=10&&i==in)
std::cout<<" "<<i<<" "<<g_buffer[i];
if(i==out)
{
if(g_buffer[i]<10)
std::cout<<" ";
else
std::cout<<" ";
std::cout<<" <-- 消费者";//输出消费者的指针位置
}
std::cout<<std::endl;
}
}
/*----------------------把新生产的产品放入缓冲区结束------------------------*/
/*----------------------------消费一个产品开始------------------------------*/ void Consume()//消费一个产品
{
system("color 3a");
std::cout<<std::endl;
std::cerr<<" "<<"消费一个产品: "<<ConsumeID;
std::cout<<std::endl;
}
/*----------------------------消费一个产品结束------------------------------*/
/*-----------------------从缓冲区中取出一个产品开始-------------------------*/ //从缓冲区中取出一个产品
void Take()
{
std::cout<<std::endl;
std::cerr<<" "<<"从缓冲区取出一个产品";
ConsumeID=g_buffer[out];
g_buffer[out]=0;
out=(out+1)%SIZE_OF_BUFFER;
std::cerr<<std::endl;
std::cout<<std::endl;
std::cout<<" 缓冲区产品"<<std::endl;
//取出一个产品后,输出缓冲区当前的状态
for(int i=0;i<SIZE_OF_BUFFER;++i)
{
if(i==in)
{
if(g_buffer[i]<10)
std::cout<<" ";
else
std::cout<<" ";
std::cout<<"生产者-->";//输出生产者的指针位置
// std::cout<<" ";
}
//输出缓冲区下标
if (i<10&&i!=in)
std::cout<<" "<<i<<" "<<g_buffer[i];
else if(i<10&&i==in)
std::cout<<" "<<i<<" "<<g_buffer[i];
else if(i>=10&&i!=in)
std::cout<<" "<<i<<" "<<g_buffer[i];
else if(i>=10&&i==in)
std::cout<<" "<<i<<" "<<g_buffer[i];
if(i==out)
{
if(g_buffer[i]<10)
std::cout<<" ";
else
std::cout<<" ";
std::cout<<" <-- 消费者";//输出消费者的指针位置
}
std::cout<<std::endl;
}
}
/*-----------------------从缓冲区中取出一个产品结束-------------------------*/
/*-----------------------------生产者线程开始-------------------------------*/ //生产者线程
DWORD WINAPI Producer(LPVOID lpPara)
{
while(g_continue)
{
//资源信号量的P操作
WaitForSingleObject(g_hFullSemaphore,INFINITE);
//互斥信号量的P操作
WaitForSingleObject(g_hMutex,INFINITE);
//生产一个产品
Produce();
//把新生产的产品放入缓冲区
Append();
Sleep(2000);
//互斥信号量的V操作
ReleaseMutex(g_hMutex);
//资源信号量的V操作
ReleaseSemaphore(g_hEmptySemaphore,1,NULL);
}
return 0;
}
/*-----------------------------生产者线程结束-------------------------------*/
/*-----------------------------消费者线程开始-------------------------------*/ //消费者线程
DWORD WINAPI Consumer(LPVOID lpPara)
{
while(g_continue)
{
//资源信号量的P操作
WaitForSingleObject(g_hEmptySemaphore,INFINITE);
//互斥信号量的P操作
WaitForSingleObject(g_hMutex,INFINITE);
//从缓冲区中取出一个产品
Take();
//消费一个产品
Consume();
Sleep(2000);
//互斥信号量的V操作
ReleaseMutex(g_hMutex);
//资源信号量的V操作
ReleaseSemaphore(g_hFullSemaphore,1,NULL);
}
return 0;
}
/*-----------------------------消费者线程结束-------------------------------*/
/*---------------------------创建生产者线程开始-----------------------------*/ void createPT()//创建生产者线程
{
for(int i=0;i<PRODUCERS_COUNT;++i)
{
hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);
if(hThreads[i]==NULL)
g_continue=0;
}
}
void createCT()//创建消费者线程
{
for (int j=0;j<CONSUMERS_COUNT;++j)
{// 线程栈大小
返回的ID
hThreads[PRODUCERS_COUNT+j]=CreateThread(NULL,0,Consumer,NULL,0,&consumerID [j]);
if (hThreads[j]==NULL)
g_continue=0;
}
}
/*---------------------------创建生产者线程结束-----------------------------*/ /*HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpsa, //lpsa:线程句柄的安全属性,比如子进程是否可以继承这个线程句柄,一般情况设置为NULL
DWORD cbStack, //cbStack:线程栈大小,一般取0表示默认大小
LPTHREAD_START_ROUTINE lpStartAddr, //lpStartAddr:线程入口函数 typedef DWORD (__stdcall *LPTHREAD_START_ROUTINE) (
void* lpThreadParameter );在win32程序中默认的调用函数约定就是WINAPI ,__stdcall = WINAPI 。
LPVOID lpvThreadParam //DWORD WINAPI ThreadProc( void* lpParamete) 线程中你要做的事情就是线程入口函数的参数,就是ThreadProc( void* lpParamete) 的参数
DWORD fdwCreate, //控制线程创建的标志一般为0,表示线程立即启动。
LPDWORD lpIDThread //是线程ID返回值,这个用来接收线程返回的ID
);*/
/*---------------------------创建消费者线程开始-----------------------------*/ void menu()
{
for(int i=0;i<8;i++)
printf("\t\t\t\n");
printf("\t\t\t──────────────\n");
printf("\t\t\t1.生产一个产品\n");
printf("\t\t\t2.消费一个产品\n");
printf("\t\t\t──────────────\n");
printf("\t\t\t请选择:");
}
/*---------------------------创建消费者线程结束-----------------------------*/
/*-------------------------------主函数开始---------------------------------*/ void main()
{
//显示程序提示信息
//info();
//menu();
//创建互斥信号量
g_hMutex=CreateMutex(NULL,FALSE,NULL);
//创建资源信号量
g_hFullSemaphore=CreateSemaphore(NULL,SIZE_OF_BUFFER-1,SIZE_OF_BUFFER-1,NUL L);//空
g_hEmptySemaphore=CreateSemaphore(NULL,0,SIZE_OF_BUFFER-1,NULL);//满
//创建生产者线程
createPT();
//创建消费者线程
createCT();
int i=0;
//不按回车键的话程序会一直运行下去
while(g_continue)
//按回车键终止程序
if(getchar())
g_continue = 0;
}
/*-------------------------------主函数结束---------------------------------*/ 十、总结
这次课程设计全是书上的内容,完成这次实验也是对课上老师讲过的一个回顾。
同时也
是对我们已经学习的东西一种检验和体现。
这次课程设计进行的一次全面的综合训练,不仅要熟知书上的内容,还要掌握大一所学
习的C语言,通过课程设计,让我们更好地掌握操作系统的原理及实现方法,加深对操作系
统基础理论和重要算法的理解,加强我们的动手能力。
同时还增加了我对学习兴趣,也知道
了以后该怎样的去学习。
十一、参考文献
【1】汤子瀛等.计算机操作系统.西安电子科技大学出版社.2004年5月
【2】付国瑜杨武周敏.计算机操作系统原理及应用上机实验指导.重庆工学院计算机
学院.2005年1月.
【3】c程序设计(第三版)谭浩强版。