睡眠理发师问题

一 问题描述
   (经典理发师问题)
 假设后街有家理发店,店里有一个理发师、一把理发椅和n把等候理发的顾客椅子。
 (1).如果没有顾客则理发师便在理发椅上看报纸;
 (2).当有一个顾客到达时,首先查看理发师在干什么,如果在看报纸则告诉理发师理发,然后坐到理发椅上开始理发;如果理发师正在理发,则查看是否有空的椅子可坐,如果有,他就坐下等待,如果没有,则离开;
 (3).理发师为一位顾客理完发后,查看是否有人等待,如有则唤醒一位为其理发,如没有则在理发椅上看报纸;
 (4).顾客不分优先级
二 问题分析
     题目中要求描述理发师和顾客的行为,因此需要两类进程Barber ()和Customer()分别描述理发师和顾客的行为。当理发师看报时顾客近来需要唤醒理发师为其理发,当有顾客时理发师为其理发,没有的时候理发师看报,因此理发师和顾客之间是同步的关系,由于每次理发师只能为一个人理发,且可供等侯的椅子有限只有n个,即理发师和椅子是临界资源,所以顾客之间是互斥的关系。故引入3个信号量和一个控制变量:1)控制变量waiting用来记录等候理发的顾客数,初值均为0;2)信号量customers用来记录等候理发的顾客数,并用作阻塞理发师进程,初值为0;3)信号量barbers用来记录正在等候顾客的理发师数,并用作阻塞顾客进程,初值为0;4)信号量mutex用于互斥,初值为1

三 问题实现
   1.PV操作代码如下:
      int  waiting=0 ; //等候理发的顾客数  
      int  chairs=n;     //为顾客准备的椅子数  
      semaphore  customers=0, barbers=0,mutex=1; 
      barber()
 {
     while(TRUE);                //理完一人,还有顾客吗?
       P(cutomers);              //若无顾客,理发师睡眠 
       P(mutex);                 //进程互斥 
       waiting := waiting – 1;   //等候顾客数少一个
       V(barbers);               //理发师去为一个顾客理发
       V(mutex);                 //开放临界区
       cut-hair( );              //正在理发}
 customer()
 {
     P(mutex);                 //进程互斥
     if (waiting)
 {     waiting := waiting+1;  // 等候顾客数加1
        V(customers);          //必要的话唤醒理发师
        V(mutex);              //开放临界区
        P(barbers);            //无理发师, 顾客坐着养神
       get-haircut( );   //一个顾客坐下等理/   }
        else
        V(mutex);                 //人满了,走吧!}
 
2.详细实现:
     椅子数目可以设置;程序采用用随机数产生顾客进程,也就是顾客按照随机数自动到来,这样更加接近现实生活;对于理发师,当顾客到来后去理发,如果没有顾客继续看报纸,当理完一个后,判断是否有等待,有则叫下一个来理发,没有的话去看报纸。对于客人,先看理发师是空闲还是忙,空闲则去理发,忙着的话则看是否有位置等待,有则坐下等,没有的话则离开。对于理发时间,是取系统时间来控制,设理发时间为10秒,当两次时间差大于等于10时表示理完叫下一位,小于则继续理发。并且还能控制是否开门营业,当理发师为10个以上顾客理发完成并且没有人在等待时,可以决定是否关门休息.
代码如下:
#include "windows.h"
#include "iostream.h"
#include "math.h"

#define random   (rand()*10000)/RAND_MAX //定义一个随机函数来产生顾客,并且使两个顾客间的时间少于10秒
int long waiting(0);    //正在等待的顾客的数目
int chairs;             //椅子的总数目
char open_door;          //开门
char close_door;         //关门
int count(0);           //顾客的号码数
int finish(0);          //理发完毕的顾客数目
DWORD a;

void cuthair()

 ::Sleep (10000);
 cout<<"理发完成 !"<<endl;      //理发师理发函数,用时10秒

}
void gethaircut()
{
 ::Sleep (10001);         //顾客被理发的函数,为了和理发师之间有所区别,比理发师理发时间长0.001秒。
 cout<<"第"<<finish<<"个顾客理发完毕,离开 "<<endl; 
}
HANDLE Mutex=::CreateMutex(NULL, FALSE, "Mutex"); //用来实现进程的互斥 
HANDLE barbers=::CreateSemaphore(NULL, 1,1, "barbers");//定义信号量来进行线程间的同步
HANDLE customers=::CreateSemaphore(NULL,0,3,"customers");


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--;                         //等待的人数减一
   ::ReleaseSemaphore(barbers,1,NULL);     //释放信号量
    ::ResumeThread(barbers);                //唤醒顾客进程
   ::ReleaseMutex(Mutex);                  //v(mutex);  
   cuthair();                              //理发
   finish++;                               //理发完毕的顾客数目加一
  }
  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>=10&&waiting==0)         //如果完成数超过10并且没有人等待
   {
    cout<<"已经为"<<finish<<"个顾客理发了,要关门下班吗?"<<endl;  //提示是否关门
             cin>>close_door;
    return close_door;
   }
   else ; 
 }
           if (close_door=='y')
      {
       cout<<"********对不起,暂停营业!********"<<endl;
           return 0;
      } 
  
}

 

四 运行结果
运行程序显示出字符界面,按照提示设置椅子数目,并决定是否开门营业,若不开门,则一直提示,开门则开始营业,顾客随机到来,程序自动运行.若理发完成数超过10并且没有人等待,则理发师可以决定是否关门休息.界面如下:



五 心得体会
     刚开始对进程操作不了解,不知道如何下手,后来请教同学,基本上搞懂了进程的同步与互斥操作的相关理论知识,又由于对MFC环境不熟悉,就在WIN32 Consol  Application 环境下编写了这个程序,调试过程中遇到不少问题,但是基本上都解决了.本来想让理发师理完10 个以上的人并且没有人在等待的时候可以决定是否关门下班,但是由于顾客线程是受随机函数控制的,时间上不容易满足该条件,程序运行中没有看到该功能的实现,有待进一步解决.
六 程序清单
   #include <iostream.h>
 #include <windows.h>
 random ();随机产生顾客的函数
 cuthair(); 理发师的理发函数
 gethaircut() 顾客被理发的函数
   Barber();理发师线程
   Customer();顾客线程
   Main();实现线程的操作

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个简单的睡眠理发师问题的 C 语言代码,可以在 Windows 系统上运行: ``` #include <stdio.h> #include <windows.h> int main() { HANDLE hSemaphore; // 信号量句柄 int i; // 创建信号量 hSemaphore = CreateSemaphore(NULL, 2, 2, NULL); if (hSemaphore == NULL) { printf("CreateSemaphore failed (%d)\n", GetLastError()); return 1; } // 创建理发师线程 HANDLE hBarberThread = CreateThread(NULL, 0, BarberThread, &hSemaphore, 0, NULL); if (hBarberThread == NULL) { printf("CreateThread failed (%d)\n", GetLastError()); return 1; } // 创建顾客线程 HANDLE hCustomerThread[10]; for (i = 0; i < 10; i++) { hCustomerThread[i] = CreateThread(NULL, 0, CustomerThread, &hSemaphore, 0, NULL); if (hCustomerThread[i] == NULL) { printf("CreateThread failed (%d)\n", GetLastError()); return 1; } Sleep(1000); } // 等待线程结束 WaitForSingleObject(hBarberThread, INFINITE); for (i = 0; i < 10; i++) { WaitForSingleObject(hCustomerThread[i], INFINITE); } // 关闭句柄 CloseHandle(hSemaphore); CloseHandle(hBarberThread); for (i = 0; i < 10; i++) { CloseHandle(hCustomerThread[i]); } return 0; } DWORD WINAPI BarberThread(LPVOID lpParam) { HANDLE hSemaphore = *(HANDLE*)lpParam; while (TRUE) { printf("Barber is sleeping...\n"); WaitForSingleObject(hSemaphore, INFINITE); // 获取信号量 printf("Barber is cutting hair...\n"); Sleep(1000); ReleaseSemaphore(hSemaphore, 1, NULL); // 释放信号量 } return 0; } DWORD WINAPI CustomerThread(LPVOID lpParam) { HANDLE hSemaphore = *(HANDLE*)lpParam; printf("Customer %d comes in...\n", GetCurrentThreadId()); WaitForSingleObject(hSemaphore, INFINITE); // 获取信号量 printf("Customer %d is getting a haircut...\n", GetCurrentThreadId()); Sleep(1000); ReleaseSemaphore(hSemaphore, 1, NULL); // 释放信号量 printf("Customer %d leaves.\n", GetCurrentThreadId()); return 0; } ``` 代码中使用了 Windows API 的信号量机制来实现对睡眠理发师问题的模拟。其中,`CreateSemaphore` 函数创建一个信号量,第二个参数指定初始计数值为 2(即有两个空闲椅子),第三个参数指定最大计数值也为 2,第四个参数为 NULL 表示不使用命名信号量。`WaitForSingleObject` 函数和 `ReleaseSemaphore` 函数分别用于获取和释放信号量。`CreateThread` 函数创建线程。`Sleep` 函数用于让顾客线程之间的到达时间有所区别。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值