睡眠理发师课程设计报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《操作系统》课程设计报告
专业:计算机科学与技术
班级:08 计本(2)班
题目名称:理发师问题
完成日期:2011 . 6
甘肃政法学院计算机科学学院
目录
一.题目内容.............................................. 错误!未定义书签。
二.课程设计目的.......................................... 错误!未定义书签。
三.设计思想说明.......................................... 错误!未定义书签。
四.系统结构的说明........................................ 错误!未定义书签。
(一)头文件声明..................................... 错误!未定义书签。
(二)定义各种变量................................... 错误!未定义书签。
(三)信号量的定义................................... 错误!未定义书签。
(四)相关函数及线程的定义........................... 错误!未定义书签。
五.数据结构说明.......................................... 错误!未定义书签。
六.程序用到的系统调用(API)............................. 错误!未定义书签。
七.程序总体算法流程图.................................... 错误!未定义书签。
八.程序运行.............................................. 错误!未定义书签。
九.使用说明书............................................ 错误!未定义书签。
十.程序设计总结.......................................... 错误!未定义书签。
参考文献................................................. 错误!未定义书签。
附录..................................................... 错误!未定义书签。
(一)代码清单....................................... 错误!未定义书签。
(二)课程设计分工表................................. 错误!未定义书签。
睡眠理发师问题
一.题目内容
有一个理发师,一把理发椅和n把提供给等候理发的顾客座的椅子。
如果没有顾客,则理发师便在理发椅子上睡觉;当第一个顾客到来时,必须唤醒该理发师进行理发;如果理发师正在理发时又有顾客到来,则如果有空椅子可坐,他就坐下来等待,如果没有空椅子,他就离开理发店。
为理发师和顾客各编一段程序描述他们的行为,要求不能带有竞争条件,试用P、V操作实现。
二.课程设计目的
通过本次课程设计,能深入彻底的弄清楚睡眠理发师问题,能够举一反三,遇到同样的问题能够很快解决。
通过自己的实际操作,认真分析,理解进程,线程,信号量之间的关系和他们的实现过程,掌握一些基本的系统调用的用法及其所实现的功能。
用C++来实现睡眠理发师的课程设计,达到复习C++相关知识的目的。
三.设计思想说明
此题可看作是n个生产者和1个消费者问题。
顾客作为生产者,每到来一个就使计数器count增加1,以便让理发师理发(相当于消费)至最后一个顾客(相当于产品)。
并且,第1个到来的顾客应负责唤醒理发师;如果不是第1个到达的顾客,则在有空椅子的情况下坐下等待,否则离开理发店(该消息可由计数器count获得)。
主要有以下一些函数来实现整个问题的实现过程:
(1)用随机函数random()来产生进入理发店的顾客。
(2)定义理发师的理发函数cuthair()用来实现理发操作。
(3)定义顾客被理发的函数gethaircut()用来实现顾客被理发的操作。
(4)用顾客线程customer实现对顾客行为的控制。
(5)用理发师线程barber实现对理发师行为的控制。
(6)定义主函数main实现对两个线程的控制和执行操作。
四.系统结构的说明
(一)头文件声明
#include "stdafx.h"
#include "windows.h"
#include "iostream.h"
#include "math.h"
(二)定义各种变量
int long waiting(0);
int chairs;
char open_door;
char close_door;
int count(0);
int finish(0);
(三)信号量的定义
DWORD a;%互斥信号量:mutex 用来互斥对临界变量count的访问
计数信号量customers用来记录等候的顾客数据,barbers用来记录等待的理发师数,这里barbers只
有两种取值,要不是0要不是1
临界变量:count由理发师进程和顾客进程共同访问,用来记录在椅子上等着的顾客数
N 椅子数,为最多等候的顾客数
HANDLE Mutex =::CreateMutex(NULL, FALSE, "Mutex");
HANDLE barbers =::CreateSemaphore(NULL, 1,1, "barbers");
HANDLE customers =::CreateSemaphore(NULL,0,3,"customers");
(四)相关函数及线程的定义
定义随机函数int random()来产生顾客,并使两个顾客间的时间少于15秒
定义理发师的理发函数void cuthair(),用时15秒
定义顾客被理发的函数void gethaircut()
定义顾客线程DWORD WINAPI customer(LPVOID pParm2)
定义理发师线程DWORD WINAPI barber(LPVOID pParm1)
定义主函数实现线程的操作int main(int argc, char* argv[])
五.数据结构说明
本程序用到了数据结构中的队列,理发的顾客由随机函数产生,顾客遵从先到先理发的原则,但队列的长度限制为输入的理发店中的椅子的个数,当理发店的椅子没有空位的时候,到来的顾客主动退出加入队列。
理发师对队列中的顾客进行先到先服务的原则理发。
六.程序用到的系统调用(API)
(1)CreateThread():创建线程
(2)CreateMutex():找出当前系统是否已经存在指定进程的实例。
如果没有则创建一个互斥体,用来同步。
如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。
CreateMutex()函数可用来创建一个有名或无名的互斥量对象
(3)CreateSemaphore():CreateSemaphore() 是系统提供的API,包含在Windows.h 中,应用在同步的处理中。
作用是创建一个新的信号机,执行成功,返回信号机对象的句柄;零表示出错。
一旦不再需要,一定记住用CloseHandle关闭信号机的句柄。
它的所有句柄都关闭以后,对象自己也会删除。
一旦值大于零,信号机就会触发(发出信号)。
Semaphore是一个同步问题机制,不论是Event或Mutex,其他Process在执WaitForSingleObject时,就看当时的物件是Signal或UnSignal而决定是否等待,而Semaphore也相同,但是它要变成Signal /UnSignal的状态,却有些不同,它是提供一个计数值,它允许在这个计数值之内,任何执行到WaitForSingleObject的Thread都不会停下来,而且每执行WaitForSingleObject 一次,计数值就减一,当计数值变成0时,该Semaphore才会处於UnSignal的状态,而某个Thread ReleaseSemaphore时,便会将计数值增加,以便其他的Thread或本身可得Signal 的讯号,而使WaitForSingleObject停止等待。
(4)ReleaseSemaphore():ReleaseSemaphore()函数的作用是增加信号机的计数。
如果成功,就调用信号机上的一个等待函数来减少它的计数。
(5)WaitForSingleObject():函数用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。
参数dwMilliseconds有两个具有特殊意
义的值:0和INFINITE。
若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。
(6)ResumeThread():线程恢复函数,使用该函数能激活线程的运行,使CPU分配资源让线程恢复运行。
(7)ReleaseMutex():释放由线程拥有的一个互斥体
(8)Sleep():睡眠等待
七.程序总体算法流程图
八.程序运行
(1)键入店中的椅子数
(2)键入椅子数后询问是否接待顾客
(3)开始接待顾客,第一个顾客到来
(4)依次有顾客到来
(5)还有顾客依次到来
九.使用说明书
打开VC++6.00编译环境,新建工程名,将上述代码复制粘贴编译运行即可看到运行窗口。
然后根据窗口提示,从键盘输入椅子数并按回车键即可。
然后再根据提示,即可进行相应操作。
其中一些窗口内容如上面一些截图所示。
十.程序设计总结
通过这次课程设计,我们搜索了理发师问题的相关资料,又对课本知识进行了进一步的深入学习。
在完成该程序的编写的过程中,使我对课堂上所学的理论知识有了一个更深更具
体的认识,尤其对操作系统课程中的信号量,线程,中断等内容有了进一步的认识,并吸收整合了网络上一些优秀的代码,经历了不少艰辛,终于完成了此项任务。
总的来讲,此次课程设计对我们操作系统知识的巩固起了重要作用,让我们受到了很多启发,懂得了怎样更好的去学习操作系统课程。
在做的过程中也遇到很多问题。
主要有:为什么现在我在vs2005中编写c++程序还要加上#include "stdafx.h"这么一句,不加就报错?名称的英文全称为:Standard Application Framework Extensions 。
分析原因如下
头文件预编译,就是把一个工程(Project)中使用的一些MFC标准头文件(如Windows.H、Afxwin.H)预先编译,以后该工程编译时,不再编译这部分头文件,仅仅使用预编译的结果。
这样可以加快编译速度,节省时间。
预编译头文件通过编译stdafx.cpp生成,以工程名命名,由于预编译的头文件的后缀是“pch”,所以编译结果文件是projectname.pch。
(一)代码清单
#include "stdafx.h"
#include "windows.h"
#include "iostream.h"
#include "math.h"
int long waiting(0); //等待理发的顾客人数
int chairs; //店中椅子的总数目
char open_door; //开门
char close_door; //关门
int count(0); //顾客的序号
int finish(0); //已经理完发的顾客人数
DWORD a;(无符号整数32位)
HANDLE Mutex =::CreateMutex(NULL, FALSE, "Mutex"); //用来实现进程的互斥HANDLE barbers =::CreateSemaphore(NULL, 1,1, "barbers"); //定义信号量来进行线程间的同步
HANDLE customers =::CreateSemaphore(NULL,0,3,"customers"); //定义信号量来进行线程间的同步
int random()
//定义随机函数来产生顾客,并使两个顾客间的时间少于15秒
{
return (rand()*15000)/RAND_MAX;
}
void cuthair()
//理发师的理发函数,用时15秒
{
::Sleep (15000);
cout<<"理发结束!"<<endl;
}
void gethaircut()
// 顾客被理发的函数
{
::Sleep (15001); //顾客被理发的函数,为了和理发师之间有所区别,比理发师理发时间长1毫秒
cout<<"第"<<finish<<"个顾客理发完毕,离开"<<endl;
}
DWORD WINAPI customer(LPVOID pParm2)
// 顾客线程
{
::WaitForSingleObject(Mutex ,INFINITE); //P(mutex)来进行互斥操作
count++; //来的是第几个顾客
cout<<"顾客敲门!第"<<count<<" 个顾客到来"<<endl;
if (waiting<chairs) //如果有空椅子
{
if (waiting!=0)
{
cout<<"现在有"<<waiting <<" 个人在等待理发"<<endl;
}
else
cout<<"无人在等待理发"<<endl; //输出有多少人在等待waiting++;
cout<<"剩余"<<chairs-waiting+1<<"个座位"<<endl;
cout<<"有空位,顾客已坐下"<<endl;
::ReleaseSemaphore(customers,1,NULL); //V(customer)
::ResumeThread(customers); //唤醒理发师进程
::ReleaseMutex(Mutex); //释放互斥量,以便其他线程使用
::WaitForSingleObject(barbers,INFINITE);//等待理发
gethaircut(); //理发并离开
}
else
{
cout<<"没有空椅子,第"<<count<<"个顾客离开理发店"<<endl; //没有椅子,顾客直接离开
::ReleaseMutex(Mutex);
}
return 0;
}
DWORD WINAPI barber(LPVOID pParm1)
//理发师线程
{
while(true)
//外循环
{
::WaitForSingleObject(customers,INFINITE);//p(customers),等待顾客
::WaitForSingleObject(Mutex,INFINITE); //等待互斥量
waiting--; //等待的人数减1
::ReleaseSemaphore(barbers,1,NULL); //释放信号量
::ResumeThread(barbers); //唤醒顾客进程
::ReleaseMutex(Mutex); //v(mutex);
cuthair(); //理发
finish++; //理发完毕的顾客数目加1 }
return 0;
}
int main(int argc, char* argv[])
//实现线程的操作
{
cout<<"输入理发店中的椅子个数:";
cin>>chairs;
cout<<"店中有"<<chairs<<"把椅子"<<endl; //设置椅子数目
cout<<"是否开始接待顾客?Y/N"<<endl; //是否开门营业
cin>>open_door;
while (open_door!='y')
{
cout<<endl<<"尚未营业!"<<endl;
cout<<"是否开始接待顾客?Y/N"<<endl;
cin>>open_door;
}
HANDLE hThread1;
HANDLE hThread2;
hThread2=::CreateThread (NULL,0,barber,NULL,0,NULL); //产生一个理发师进程
while(close_door!='y')
{
::Sleep(random());//函数实现顾客随机到来
hThread1=::CreateThread(NULL,0,customer,NULL,a,NULL);
cout<<endl<<"正在营业,请进!"<<endl;
if (finish>=8 && waiting==0)
//如果完成数超过8并且没有人等待
{
cout<<"已经为"<<finish<<"个顾客理发了,是否停止营业?"<<endl; //提示是否关门
cin>>close_door;
return close_door;
}
}
if (close_door=='y')
{
cout<<"暂停营业!欢迎下次光临!"<<endl;
return 0;
}
return 0;
}。