设计思想的说明:
打瞌睡的理发师问题是一种同步问题的抽象描述。
计算机系统中的每个进程都可以消费或生产某类资源,当系统中某一进程使用某一资源时,可以看作是消耗,且该进程称为消费者。
而当某个进程释放资源时,则它就相当一个生产者。
因此此题可看作是n个生产者和1个消费者问题。
顾客作为生产者,每到来一个就使计数器count增加1,以便让理发师理发(相当于消费)至最后一个顾客(相当于产品)。
并且,第1个到来的顾客应负责唤醒理发师;如果不是第1个到达的顾客,则在有空椅子的情况下坐下等待,否则离开理发店(该消息可由计数器count获得),所以可以通过一个有界缓冲区把理发师和顾客联系起来通过对信号进行P、V操作来实现有关问题和相关描述。
源程序文件:
#include<windows.h>
#include<stdio.h>
#include<iostream>
#include<process.h>
#include<conio.h>
#include<ctime>
using namespace std;
#define CHAIRS 3 //椅子的个数
#define BARBERS 1 //理发师的个数
#define CUSTOMESTOCOME 7 //将要来的顾客的数目
typedef HANDLE semaphore;
static int count=0; //记录理发店顾客的总数,初始化为0
int leaved=0; //记录理发店顾客的总数,初始化为0
int waiting=0;
time_t endtime; //关闭营业的时间
//coustomers初始化为0,最大顾客数为3
semaphore customers=CreateSemaphore(NULL,0,CHAIRS,TEXT("customers")); //barbers的数量初始化为1,假设一共有1个barber
semaphore
barbers=CreateSemaphore(NULL,BARBERS,BARBERS,TEXT("barbers"));
//建立互斥变量,用于保护共享资源
HANDLE mutex=CreateMutex(NULL,FALSE,TEXT("mutex"));
DWORD WINAPI barber(LPVOID lparameter);
DWORD WINAPI customer(LPVOID lparameter);
//理发师理发
void cutHair();
//顾客坐到椅子上等待
void getChair();
//等待顾客到来
void wait();
//顾客离开
void customerLeave();
//顾客进入
void customerEnter();
void up(HANDLE hHandle){
//对指定信号量增加指定的值
ReleaseSemaphore(hHandle,1,NULL);
//恢复线程
ResumeThread(hHandle);
}
void upMutex(HANDLE hMutex){
//释放线程拥有的互斥体
ReleaseMutex(hMutex);
}
void down(HANDLE hHandle){ //DOWN operation
//线程挂起,等待信号
WaitForSingleObject(hHandle,INFINITE);
}
int main(){
//结束时间
endtime=time(0)+20000;
//创建理发师线程
HANDLE barberThread=CreateThread(NULL,0,barber,NULL,0,NULL);
HANDLE customerThread;
//产生10个客户进程,每两个进程之间间隔一个随见时间1000~1050 while(count<CUSTOMESTOCOME)
{
//创建客户进程
customerThread=CreateThread(NULL,0,customer,NULL,0,NULL);
srand(unsigned(time(0)));
int time=rand()%1000+50;
Sleep(time);
}
//释放资源
CloseHandle(barberThread);
CloseHandle(customerThread);
CloseHandle(barbers);
CloseHandle(customers);
CloseHandle(mutex);
cout<<"离开的顾客总数为:"<<leaved<<endl;
return 0;
}
DWORD WINAPI barber(LPVOID lparameter) {
while(time(0)<endtime)
{
//没有客户,则进入睡眠状态
down(customers);
//临界区操作
down(mutex);
waiting=waiting-1;
upMutex(mutex);
//开始理发
cutHair();
//理发结束,理发师信号量加1
up(barbers);
}
return 0;
}
DWORD WINAPI customer(LPVOID lparameter){ //客户到来
customerEnter();
//临界区操作
down(mutex);
cout<<"等̨¨待äy的Ì?顾?客¨ª数ºy: "<<waiting<<endl;
cout<<"空?椅°?子Á¨®数ºy: "<<CHAIRS-waiting<<endl;
if(waiting<CHAIRS)
{ //如果有空椅子,客户等待,否则离开
if(waiting!=0)
{
//等待顾客到来
wait();
}
waiting=waiting+1;
//客户信号量加1
up(customers);
upMutex(mutex);//离开临界区
//理发师进程等待唤醒
down(barbers);
//顾客坐下来等待
getChair();
}
else
{
//释放互斥锁
upMutex(mutex);
//顾客离开
customerLeave();
}
return 0;
}
void cutHair(){
static int served=0;
served++;
cout<<理发师帮第"<<served<<"位被服务的顾客理发"<<endl;
Sleep(1000);
cout<<"第"<<served<<"位被服务的顾客理完发"<<endl;
}
void getChair(){
Sleep(1050);
}
void customerEnter(){
count++;
SYSTEMTIME sys;
GetLocalTime( &sys );
cout<<endl<<"第"<<count<<"位顾客进来"<<endl;
}
void wait(){
cout<<"有空位,第"<<count<<"位顾客就坐"<<endl;
}
void customerLeave(){
cout<<"没有空椅子,第"<<count<<"位顾客离开 ."<<endl;
leaved++;
}
输出截图:
PS:由于我对c++中处理进程、信号的函数不熟,所以有许多参考了网上的代码。
我尽量去读懂代码,并自己写上注释。