生产者消费者模拟Word格式文档下载.docx
《生产者消费者模拟Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《生产者消费者模拟Word格式文档下载.docx(24页珍藏版)》请在冰点文库上搜索。
![生产者消费者模拟Word格式文档下载.docx](https://file1.bingdoc.com/fileroot1/2023-5/6/9f4e4fba-e99d-41fa-a214-77e02a620c8f/9f4e4fba-e99d-41fa-a214-77e02a620c8f1.gif)
3)生产者的生产速度与消费者的消费速度均可在程序界面调节
4)多个生产者或多个消费者之间必须有共享对缓冲区进行操作的函数代码
5)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容、
当前生产者与消费者的指针位置,以及生产者和消费者线程标识符
三、系统分析与设计
1、系统分析:
在学习进程互斥中,生产者-消费者问题是一个经典的,具有代表性的进程同步问题。
一个有限缓冲池和两类线程,它们是生产者和消费者,生产者把产品放入缓冲区,相反消费者便是从缓冲区中拿走产品。
两个线程对同一有限缓冲区的互斥访问是该问题有很大的代表性以及使用价值的根本原因。
该问题可以用三种方法实现,第一种是利用记录型信号量机制解决,第二种是利用AND信号量机制解决,第三种是利用管程机制解决。
本程序使用第一种方式实现。
假定在生产者和消费者之间有一个大小为100的缓冲区,这时可利用互斥信号量wait来实现诸进程对缓冲池的互斥使用。
利用信号量empty表示缓冲区中空缓冲区的数量。
对缓冲池的访问有如下规则:
只用缓冲区未满,生产者便可对其进行访问,但只能有一个生产者进行访问,其他不能进行访问;
只要缓冲区未空,消费者便可对其进行消费取走商品,且可以有多个消费者同时进行消费。
生产者在缓冲区满时必须等待,直到缓冲区有空间才继续生产。
同时当有另一生产者进行对缓冲池访问时也必须等待。
消费者在缓冲区空时必须等待,直到缓冲区中有产品才能继续消费。
2、系统设计:
程序的整个过程如下图所示,主界面时可以选择不同的登录界面,在选择生产者登录界
面时,根据不同的需要进行修改。
在登录消费者界面时,也可以根据不同的选择进行更改变量,同时进行数据的更新。
3、模块设计:
系统界面分为生产者界面和消费者界面,不同界面为不同用户使用。
以下是不同用户的使用设计。
各程序模块之间的调用关系如下图所示:
(1)信号量初始化模块
生产者消费者中使用了两个同步信号量和一个互斥信号量定义了。
同步信号量empty_sem初值为20,sem_init(&
empty_sem,0,20),full_sem初值为0,sem_init(&
full_sem,0,0),用默认属性初始化一个互斥锁对象pthread_mutex_init(&
mutex,NULL)。
(2)生产者线程模块
使用变量countp进行while循环的控制,当countp<
20时进入while循环。
在循环中判断同步信号量empty_sem和互斥信号量mutex,使用语句sem_wait(&
empty_sem),pthread_mutex_lock(&
mutex)。
然后生产数据,放入缓冲区中。
用指针in控制放入缓冲区的位置,用countp++进行循环的控制。
(3)消费者线程模块
使用变量countc进行while循环的控制,当countc<
在循环中判断同步信号量full_sem和互斥信号量mutex,使用语句sem_wait(&
full_sem),pthread_mutex_lock(&
然后消费数据,从缓冲区中取出。
用指针out控制取走缓冲区的位置,用countc++进行循环的控制。
(4)主函数模块
定义了三个消费者线程和三个生产者线程。
调用信号量初始化函数。
使用函数pthread_create用来创建线程,以及用函数pthread_join用来等待一个线程的结束
。
4、数据结构说明:
intm_Time;
//执行间隔HANDLEm_Thread;
//线程句柄HANDLEm_hStopEvent;
//退出线程事件StoreHouse*m_pHouse;
//货仓指针CCustomerDlg*m_pDialog;
//对话框指针voidSetHouse(StoreHouse*pHouse){m_pHouse=pHouse;
}//设置仓库voidSetDialog(CCustomerDlg*pDlg){m_pDialog=pDlg;
}//设置对话框virtualvoidDo()=0;
//执行操作virtualvoidStart(intspeed);
//开始运行
virtualvoidStop();
//结束运行intm_nCurrentSize;
//当时仓储量intm_nMaxSize;
//最大仓储量REFRESH_FUNCm_RefreshFunc;
//刷新回调函数void*m_pParam;
//回调函数的参数CRITICAL_SECTIONm_csLock;
//本实例锁HANDLEm_hEventGoods;
//此事件置信则表示仓库有货HANDLEm_hEventHouse;
//此事件置信则标识仓库有空位HANDLEm_hStopEvents;
//仓库倒塌,所有工作者线程停止运行voidSetMaxSize(intnMaxSize=DEFAULT_SIZE);
//设置最大仓储量intGetMaxSize(void);
//得到最大尺寸intGetCurrentSize(void);
//得到当时仓储量voidCheckStore(void);
//检查仓库
5、算法流程图:
四、模块调试与系统测试
1、模块调试
●输入形式和输入值的范围
生产消费速度输入值的范围为1~20之间。
●输出形式
(1)生产者:
在相应位置显示所生产的产品名称以及数量
(2)消费者:
在相应的位置显示消费情况
●程序所能达到的功能
模拟仿真“生产者-消费者”问题的解决过程及方法。
当生产者生产进入生产状态时,其他生产者就不能进行生产和访问缓冲池,而消费者则可以进行访问,并进行消费产品。
测
试
说
明
测试名称
测试目的
验证系统的合理性
测试技术
数据测试
测试方法
黑盒测试
用
例
测试内容
测试程序的正确性
测试步骤
输入生产消费速度,启动仓库,增加生产者消费者的数目
测试数据
生产者速度1,消费者速度1
预期结果
能正常运行
测试结果
正常运行
2、系统测试
3、调试分析:
1、使用时间控件是为了防止界面刷新太快而被锁死,无法点击,默认500毫秒刷新一下工作者产生的信息,下面是关键代码。
voidCCustomerDlg:
:
OnTimer(UINTnIDEvent)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
if(nIDEvent==MESSAGE_TIMER)
{
inti;
CStringszOldMessage;
CStringszMessage;
GetDlgItem(IDC_EDIT_MESSAGE)->
GetWindowText(szOldMessage);
EnterCriticalSection(&
m_csMessages_Lock);
if(m_Messages.GetSize()<
=0)
{
LeaveCriticalSection(&
return;
}
for(i=0;
i<
m_Messages.GetSize();
i++)
szMessage=m_Messages.ElementAt(i);
szOldMessage=szOldMessage+szMessage;
m_Messages.RemoveAll();
LeaveCriticalSection(&
SetWindowText(szOldMessage);
((CEdit*)GetDlgItem(IDC_EDIT_MESSAGE))->
LineScroll(10000);
}
CDialog:
OnTimer(nIDEvent);
}
五、用户手册
1.本程序是在MicrosoftWindowsXPSP3环境下编写的,运行平台可为Windows95/98/Windows2000/WindowsXP/Windowsvista/Windows7。
2.本程序是可视化的界面,可以直接运行可执行文件。
3.运行程序后,分别输入生产消费的速度,注意输入的时候为1-20之间的任意数字,然后启动仓库就可以了,在运行的过程中可以随时更改生产者消费者的数量。
4.程序的主界面如下:
六、程序清单
//CAboutDlgdialogusedforAppAbout
classCAboutDlg:
publicCDialog
public:
CAboutDlg();
//DialogData
//{{AFX_DATA(CAboutDlg)
enum{IDD=IDD_ABOUTBOX};
//}}AFX_DATA
//ClassWizardgeneratedvirtualfunctionoverrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtualvoidDoDataExchange(CDataExchange*pDX);
//DDX/DDVsupport
//}}AFX_VIRTUAL
//Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg:
CAboutDlg():
CDialog(CAboutDlg:
IDD)
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
voidCAboutDlg:
DoDataExchange(CDataExchange*pDX)
DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
BEGIN_MESSAGE_MAP(CAboutDlg,CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
//Nomessagehandlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//CCustomerDlgdialog
CCustomerDlg:
CCustomerDlg(CWnd*pParent/*=NULL*/)
:
CDialog(CCustomerDlg:
IDD,pParent)
//{{AFX_DATA_INIT(CCustomerDlg)
m_ps=0;
m_cs=0;
m_hIcon=AfxGetApp()->
LoadIcon(IDR_MAINFRAME);
m_pHouse=NULL;
m_nProductors=0;
m_nConsumers=0;
InitializeCriticalSection(&
~CCustomerDlg()
DeleteCriticalSection(&
//{{AFX_DATA_MAP(CCustomerDlg)
DDX_Control(pDX,IDC_PROGRESS_STORE,m_StoreNums);
DDX_Text(pDX,IDC_EDIT_PS,m_ps);
DDV_MinMaxInt(pDX,m_ps,1,20);
DDX_Text(pDX,IDC_EDIT_CS,m_cs);
DDV_MinMaxInt(pDX,m_cs,1,20);
BEGIN_MESSAGE_MAP(CCustomerDlg,CDialog)
//{{AFX_MSG_MAP(CCustomerDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_START,OnButtonStart)
ON_BN_CLICKED(IDC_BUTTON_STOP,OnButtonStop)
ON_BN_CLICKED(IDC_BUTTON_ADDP,OnButtonAddp)
ON_BN_CLICKED(IDC_BUTTON_ADDC,OnButtonAddc)
ON_WM_CLOSE()
ON_WM_TIMER()
//CCustomerDlgmessagehandlers
BOOLCCustomerDlg:
OnInitDialog()
OnInitDialog();
//Add"
About..."
menuitemtosystemmenu.
//IDM_ABOUTBOXmustbeinthesystemcommandrange.
ASSERT((IDM_ABOUTBOX&
0xFFF0)==IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX<
0xF000);
CMenu*pSysMenu=GetSystemMenu(FALSE);
if(pSysMenu!
=NULL)
CStringstrAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if(!
strAboutMenu.IsEmpty())
pSysMenu->
AppendMenu(MF_SEPARATOR);
AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);
SetIcon(m_hIcon,TRUE);
//Setbigicon
SetIcon(m_hIcon,FALSE);
//Setsmallicon
Addextrainitializationhere
GetDlgItem(IDC_BUTTON_START)->
EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_STOP)->
EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_ADDC)->
GetDlgItem(IDC_BUTTON_ADDP)->
SetTimer(MESSAGE_TIMER,TIMER_INVAL,NULL);
returnTRUE;
//returnTRUEunlessyousetthefocustoacontrol
theframework.
OnPaint()
if(IsIconic())
CPaintDCdc(this);
//devicecontextforpainting
SendMessage(WM_ICONERASEBKGND,(WPARAM)dc.GetSafeHdc(),0);
//Centericoninclientrectangle
intcxIcon=GetSystemMetrics(SM_CXICON);
intcyIcon=GetSystemMetrics(SM_CYICON);
CRectrect;
GetClientRect(&
rect);
intx=(rect.Width()-cxIcon+1)/2;
inty=(rect.Height()-cyIcon+1)/2;
//Drawtheicon
dc.DrawIcon(x,y,m_hIcon);
else
//CDialog:
OnPaint();
CRectrect;
GetClientRect(&
CDCdcMem;
dcMem.CreateCompatibleDC(&
dc);
CBitmapbmpBackground;
bmpBackground.LoadBitmap(IDB_BITMAP1);
//IDB_BITMAP是你自己的图对应的ID,由于我刚刚加入的位图资源
//被我命名成了IDB_Bg,因而我这句就是bmpBackground.LoadBitmap(IDB_Bg);
BITMAPbitmap;
bmpBackground.GetBitmap(&
bitmap);
CBitmap*pbmpOld=dcMem.SelectObject(&
bmpBackground);
dc.StretchBlt(0,0,rect.Width(),rect.Height(),&
dcMem,0,0,
bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);
HCURSORCCustomerDlg:
OnQueryDragIcon()
return(HCURSOR)m_hIcon;
Refresh(void*pParam,StoreHouse*pHouse)
if(pParam==NULL
||pHouse==NULL)
return;
CCustomerDlg*pThis=(CCustomerDlg*)pParam;
chartempBuffer[BUFF_SIZE64];
_snprintf(tempBuffer,BUFF_SIZE64,"
%d"
pHouse->
GetCurrentSize());
pThis->
GetDlgItem(IDC_STATIC_CURRENT)->
SetWindowText(tempBuffer);
m_StoreNums.SetPos(pHouse->
ShowMessage(constchar*pMessage)
CStringszMessage;
szMessage.Format("
%s%c%c"
pMessage,13,10);
EnterCriticalSection(&
m_Messages.Add(szMessage);
LeaveCriticalSection(&
OnButtonStart()
Addyourcontrolnotificationhandlercodehere
if(m_pHouse!
m_pHouse=newStoreHouse;
m_pHouse->
SetRefresh(Refresh,this);
m_StoreNums.SetRange(0,m_pHouse->
GetMaxSize());
UpdateData(TRUE);
//获取速度
TRACE("
%d,%d"
m_cs,m_ps);
m_pHouse->
GetDlgItem(IDC_STATIC_MAX)->
GetDlgItem(IDC_STATIC_CURRENT)->
SetWindowText("
0"
);
GetD