完整word版操作系统 缓冲池的模拟使用word文档良心出品
GDOU-B-11-112
广东海洋大学学生实验报告书(学生用表)
、实验目的
(1)掌握缓冲池的结构 (2 )掌握缓冲池的使用方法
二、实验内容
1、 实现输入、计算、输出进程并发执行;
2、 实现getBuf 和putBuf 函数。
三、实验步骤
1、 整体设计,包括三个线程的模拟设计,三个队列的链表设计, 队列
的同步与互斥的设计等;
2、 由于本次实验没有需要太多的数据结构,因此,数据结构的设计就只有 三个缓冲队列
的设计:先构造一个空的缓冲队列,该队列是一个实体,即旦 确定的有结点的链表,它是模拟缓冲池的载体,输入与输出队列在构造时只有它 的头尾指针,而没有它的实体,这是因为它可以从空缓冲区里获得,例如,当计
算线程要数据计算时,便可从空队列里获取一个缓冲区,作为输入缓冲使用再把 它挂载到输入队列的队尾中去
由于要写的内容比较多,这里就不再废话连篇了,先把代码贴出来,里面有 着注释呢,大家都懂的:
头文件如下:
//缓冲队列类型的定义 #defi ne EMQ #defi ne INQ
实验名称
缓冲池的模拟使用
课程名称 操作系统 课程号
学院(系) 软件学院 专业 软件工程
班级软件1103
学生姓名
钟海楼
学号2010117013** 实验地点
04004
实验日期2012-05-08
还有三个
〃空缓冲队列
1
〃输入缓冲队列
#defi ne OUTQ 2 〃输出缓冲队列
〃显示的宏定义
#defi ne show1
III
#defi ne show2
III
#defi ne show3
III
const int bufferpoolsize = 50;
////缓冲池大小,默认设置为50个
〃结束运行标志
short int m_end ;
〃缓冲结构体的定义
typedef struct Buffer {
int BufNo;
〃缓冲区号
int buf; 〃缓冲内容 Buffer *n ext; //缓冲指向下一个指针
} buffer;
//线程函数声明
DWORD WINAPI InputThreadFunc(LPVOID IpPara); // 输入线程函数 DWORD WINAPI
OutputThreadFunc(LPVOID IpPara); // 输出线程函数 DWORD WINAPI CalThreadFunc(LPVOID IpPara); //
计算线程函数
by CLC
软件 1103
〃加入与摘取队列函数声明
void pu tBuf(i nt type , buffer *buf);
buffer* getBuf(i nt typ e);
//挂载到队列尾
//从队列头中摘取一个缓冲区
〃构造缓冲池函数的声明
void Con structBuffer();
〃线程的句柄
HANDLE hl npu tT; HANDLE hOut pu tT; HANDLE hCalculateT;
〃输入线程 〃输出线程
〃计算线程
//线程的ID DWORD Inpu tTid; DWORD Out pu tTid;
DWORD CalculateTid; 〃输入线程 〃输出线程
〃计算线程
〃三个互斥量信号句柄
HANDLE hmutexEMQ; HANDLE hmutexOUTQ; HANDLE hmutexINQ;
〃三个同步信号量
HANDLE hsemINQ; HANDLE hsemOUTQ; HANDLE hsemEMQ;
Cpp 的内容如下:
#i nclude "wi ndows.h" #i nclude "iostream" #i nclude "stdlib.h" #i nclude "time.h" #in clude "Mai n1.h" using n ames pace std;
//三个缓冲队列头与尾指针 buffer *hemq , *hi nq , *houtq; buffer *lemq , *li nq , *loutq;
//主函数 int main() {
cout< Co nstructBufferO; // 构造缓冲池 //创建互斥对象 hmutexEMQ = CreateMutex(NULL,FALSE,NULL); hmutexOUTQ = CreateMutex(NULL,FALSE,NULL); hmutexINQ = CreateMutex(NULL,FALSE,NULL); 〃创建信号量对象 hsemINQ = CreateSema phore(NULL,O,bufferpoolsize,NULL); hsemOUTQ = CreateSema phore(NULL,0,bufferpoolsize,NULL); hsemEMQ = CreateSema phore(NULL,bufferpoolsize,bufferpoolsize,NULL); 〃创建线程 〃空队列的互斥信号量 〃装满输出队列的互斥信号量 〃装满输入队列的互斥信号量 〃队头指针 〃队尾指针 hInputT = CreateThread(NULL,O,l np utThreadFu nc,NULL,0,&lnpu tTid); Slee p(10); hCalculateT = CreateThread(NULL,0,CalThreadFu nc,NULL,0,&CalculateTid); Slee p(10); hOut putT = CreateThread(NULL,0,Out putThreadFu nc,NULL,0,&Out pu tTid); //Slee p(10000); //system(" pause"); if(getchar()) { //按回车后终止程序运行 m_end = 0 ; coutvv"程序已经终止!"< } 〃等待三个线程的结束返回 WaitForSi ngleObject(hl np utT,INFINITE); WaitForSi ngleObject(hCalculateT,INFINITE); WaitForSi ngleObject(hOut pu tT,INFINITE); 〃释放线程的资源 CloseHa ndle(hl np utT); CloseHa ndle(hCalculateT); CloseHa ndle(hOut putT); return 0; } 〃输入线程函数的实现 DWORD WINAPI InputThreadFunc(LPVOID IpPara) //输入线程函数{ int nRan dom; buffer* getbuf; 〃保证每次运行时产生的随机数独立sran d(time(0)); while(m_e nd) {" Slee p(100); nRandom = rand()%100 + 1 ; //产生 1 至U 100 的随机数 //同步与互斥的控制 WaitForSi ngleObject(hsemEMQ,INFINITE); WaitForSi ngleObject(hmutexEMQ,INFINITE); getbuf = getBuf(EMQ); 〃访问空队列getbuf->buf = nRan dom ; coutvv"输入线程从"<<"缓冲单元"< --->"vv"data= "vvgetbuf->bufvve ndl; ReleaseMutex(hmutexEMQ); 〃释放互斥对象信号 //控制访问输入队列的互斥量 WaitForSi ngleObject(hmutexlNQ,INFINITE); putBuf(INQ,getbuf); 〃将输入的缓冲区挂载到输入队列的队尾 ReleaseMutex(hmutexINQ); ReleaseSema phore(hsemlNQ,1,NULL); } return 0; } 〃输出线程函数的实现 DWORD WINA PI Out pu tThreadFu nc(L PVOID IpP ara) 〃输出线程函数 { buffer* Out pu tbuf ; // 一个临时交换区 while(m_e nd) {" Slee p(100); ////同步与互斥的控制 WaitForSi ngleObject(hsemOUTQ,INFINITE); WaitForSi ngleObject(hmutexOUTQ,INFINITE); Out pu tbuf = getBuf(OUTQ) ; //从输出队列中提取一个提取输出缓冲 coutvv"输出线程从"<<"缓冲单元"< //Out pu tbuf->buf = -1 ; 〃提取完成后将该缓冲区回收 ReleaseMutex(hmutexOUTQ); WaitForSi ngleObject(hmutexEMQ,INFINITE); putBuf(EMQ,Out pu tbuf); 〃回收的把它挂载到空队列的队尾 ReleaseMutex(hmutexEMQ); ReleaseSema phore(hsemEMQ,1,NULL); } return 0; } //计算线程函数的实现 DWORD WINA PI CalThreadFu nc(L PVOID IpPara) { buffer* Calbuf1 = NULL; buffer* Calbuf2 =NULL; int nCal; while(m_e nd) {" Slee p(10); 〃因为计算线程的速度远远快于输入与输出线程,所以它的 休眠时间应很 小 ////同步与互斥的控制 WaitForSi ngleObject(hsemlNQ,INFINITE); WaitForSi ngleObject(hmutexlNQ,INFINITE); Calbuf1 = getBuf(INQ); //从输入队列中提取一个收容输入缓冲区 n Cal = Calbuf1->buf; 〃提取数据 coutvv"计算线程从"<<"缓冲单元"< "vvCalbuf1->bufvve ndl; //Calbuf->buf = -1 ; 〃系统将收回此缓冲区,表示该缓冲区已空 ReleaseMutex(hmutexINQ); WaitForSi ngleObject(hmutexEMQ,INFINITE); putBuf(EMQ,Calbuf1); ReleaseMutex(hmutexEMQ); ReleaseSema phore(hsemEMQ,1,NULL); WaitForSi ngleObject(hsemEMQ,INFINITE); WaitForSi ngleObject(hmutexEMQ,INFINITE); Calbuf2 = getBuf(EMQ); 〃得到一个空的缓冲区作为收容输出 Calbuf2->buf = n Cal ; // 存入运算结果 coutvv"计算线程从"<<"缓冲单元"< --->"vv"data= "< ReleaseMutex(hmutexEMQ); WaitForSi ngleObject(hmutexOUTQ,INFINITE); // 把收容输出缓冲区挂 载到输出队列的队尾 putBuf(OUTQ,Calbuf2); ReleaseMutex(hmutexOUTQ); ReleaseSema phore(hsemOUTQ,1,NULL); } return 0 ; //计算线程函数 nCal = nCal + 10000 ; //模拟输入数据的处理 //从队列中得到队头结点函数(实际相当于删除一个结点操作) buffer* getBuf(i nt type) { buffer* Returnbuf = NULL; switch(t ype) { case 0 : { 〃判断该队列的缓冲个数是否还只有一个 if(hemq != lemq && hemq->n ext- >n ext != NULL) { Retu rn buf = hemq->n ext ; hemq->n ext = Retu rnbuf->n ext; Returnbuf-> next = NULL; return Returnbuf; } else { 〃假如该缓冲队列的个数只有一个的话,贝u 使得队头指针与队尾 指针相等级 〃这样的话就可以防止队尾指针的丢失 Retu rn buf = hemq->n ext ; hemq->n ext = Retu mbuf->n ext; Returnbuf- >n ext = NULL; lemq = hemq ; return Returnbuf; } }break; case 1: { if(hi nq != linq && hin q-> next-> next != NULL) { Retu rn buf = hinq->n ext; hinq->n ext = Retu rnbuf->n ext; Returnbuf-> next =NULL; return Returnbuf; } else { II 取得队列头 //修正队列链表头指针的指 Retu rn buf = hinq->n ext ; hinq->n ext = Retu mbuf->n ext; Returnbuf- >n ext = NULL; linq = hinq; return Returnbuf; }break; case 2: { if(houtq != loutq && houtq-> next- >n ext !=NULL ) { Retu rn buf = houtq->n ext ; houtq->n ext = Retu rnbuf->n ext; Returnbuf- >n ext = NULL; return Returnbuf; } else { Retu rn buf = houtq->n ext; houtq->n ext = Retu rnbuf->n ext ; Returnbuf- >n ext = NULL; loutq = houtq; return Returnbuf; } }break; } } //把某一类型的缓冲区挂载到队尾函数〃(实际相当于插入一个结点操作) void pu tBuf(i nt type , buffer* buf) { switch(t ype) { case 0: { if(buf != NULL) 为插入一个空的缓冲区是没有意义的 { lemq->n ext = buf; lemq = buf ; lemq->n ext = NULL; 〃该参数(buf)不为空的时候,才执行,因 〃修正队列尾指针 //队尾指针的跟踪 //队列尾指针赋空 } }break; case 1: { if(buf != NULL) { //同上 linq->n ext = buf; linq = buf; linq-> next = NULL; } }break; case 2: { if(buf != NULL ) { loutq->n ext = buf; loutq = buf; loutq-> next = NULL; } }break; //构造缓冲池函数的声明 void Con structBuffer() { buffer *p , *q; hemq = new buffer; hinq = new buffer; houtq = new buffer; q = hemq; for(i nt i = 0 ; i < buffer po olsize ; i++) { //为开辟动态缓冲区而设的两个变量 //创建空队列的头指针 //创建输入队列的头指针 //创建输出队列的头指针 P = new buffer; p->BufNo = i; p->buf = -1 ; q->n ext = p; q = P ; //开辟新的缓冲区 //给开辟的缓冲区编号 //前一缓冲区指向新的缓冲区 //q 总是记住队尾的缓冲区 } lemq = q ; 〃空缓冲区队尾指针的确定 linq = hin q; //此时输入与输出队列的头指针与尾指针是一致的 loutq = houtq; lemq->n ext = NULL; linq->n ext = NULL; loutq->n ext = NULL; 部分运行效果截图: 'D:\MV DOCU M ENT 名;砂-与作並\£二雷二学靜提炸乘統谣码区\山ngBLifferPooE\Oebij g\U... I ■=■ I 同 魂I 缓冲池的模拟 by CLC 软 #1103 四、实验总结 1本次实验中,线程的同步与互斥和三个缓冲队列的维护是重点,在实际 编程中,刚开始 的时候没有太注重三个队列的维护,使得每次运行时都出现只有 前面几个结果,后来认真的想想,原因在于是没有对这三个缓冲队列的维护, 因 为三个队列都是以链表的形式来实现的, 因此,出现了指针指向了系统非法的内 存地址,使得运行异常中止; 2、在PutBuf()与getBufO 函数中并没有把线程访问的同步与互斥操作放 2 2 1 1 0 0 6 6 2 2 0 0 ----------------------------------------- 査J.;査J.;査J. ;査岀入入岀岀入入岀岀入入岀岀入入脅 ----------------------------------------- 一 一 一 一 一 一 一 一 一 一 一 一 一 一 一 一 一 一 一 - 001122334455667788990 00112233445566778899111111111111111111112 元元元元元元元元元元元元远迈迈迈迈迈刀丢刀丢刀丢刀丢刀丢刀丢 刀丢刀元元元丟迈刀元历 勺-yn - yn -百-yn -百-yn -百-yn -百-yn -百-yn -百 -勺-百-勺-百-勺一 百-勺 一 yn - yn 一 yn - yn 一 yn - yn 一 yn - yn 一 yn - yn 一 yn - yn 一 yn - yn 一 yn - yn - yn - yn - yn -勺 - 口 口口口口口口口口口口口口口口口口口口口口口口口口口 口口口口口口口口口口口口口口口- 日 日 日 A 人一最鼻岀人一最鼻岀人一最鼻岀人篡鼻岀人篡鼻岀人篡鼻岀人篡鼻岀人篡鼻岀人篡鼻岀入篡鼻岀入 在里面,是因为是线程调用它时,返回后需要向屏幕打印消息,这样的话,多个线程便会抢占性的在屏幕上打印消息,会造成乱码的现象;假如要在putBufO与getBufO函数中包含互斥与同步的操作,那么势必要在这两个函数里面实现打印消息的; 3、体会了多线程编程的优越性,但,如果对各线程的同步与控制不恰当时,便会造成难以预料的结果,因此,用多线程编程时必须加以注意才行! 指导教师日期成绩__________________ 注:请用A4纸书写,不够另附纸。