理发师问题--windows下C++实现

来源:互联网 发布:学美工设计 编辑:程序博客网 时间:2024/05/07 04:26

  • 理发师问题:理发店有一个出口一个入口,没顾客的时候理发师在打瞌睡,有顾客的时候理发师在椅子上等待的顾客中选出顾客来理发,顾客进店就坐在椅子上等待(也有做沙发),没有椅子坐的人就站着排队(也有的省去站着排队的环节,以下就是),连站着排队的位置也没有的时候就直接离开。它的实质是生产者和消费者的问题。
  • lock variable--用变量记录有多少顾客在等。这种做法是不行的,它无法解决以下情况:当还剩下一个位置,两个顾客同时进来,其中一个线程已经通过if判断还未++waits时,另一个线程正进行if判断,它认为也可以进去,结果就是这时两个顾客都进来了。
  • semaphore--解决这个问题就要保证critical region中只有一个线程在执行,waits这种变量也在临界区里更新,用mutex(互斥)实现。还要记录理发师、顾客数量这两个信号(semaphore)。
  • 释放信号后会唤醒一些线程,唤醒哪个不是自己控制,是库函数控制的
  • 用到的一些windowsAPI,http://blog.csdn.net/jackyguo1992/article/details/17320069。WaitForSingleObject相当于down操作,ReleaseSemaphore相当于up操作

  • 维基百科上一个理发师的伪代码,http://en.wikipedia.org/wiki/Readers-writers_problem。以下是两个理发师的问题,做的改动就是hBarbers改为0~2,初值设为0,再创建两个线程。顾客的行为是,每次在临界区更新等待人数的变量,然后出临界区,等待理发师,理发师来了之后开始被理发;理发师的行为是,等顾客来唤醒他,唤醒之后进入临界区,在临界区里更新等待人数,然后唤醒一个顾客,出临界区,开始理发。这样的过程比较符合正常思维,而且输出也没问题,这是今天讨论的结果。

#include <Windows.h>#include <cstdio>#include <ctime>#define CH 2#define BARBERS 2HANDLE hMutex, hBarbers, hCustomers;int customer_id, waits;DWORD WINAPI barber_thread(void *param);DWORD WINAPI customer_thread(void *param);DWORD WINAPI barber_thread(void *param){int my_id = *(int *)param;while(1){WaitForSingleObject(hCustomers, INFINITE);WaitForSingleObject(hMutex, INFINITE);waits--;ReleaseSemaphore(hBarbers, 1, NULL);ResumeThread(customer_thread);// call a customer to haircutReleaseMutex(hMutex);printf("%dth barber starts to haircut\n", my_id);Sleep(3000);printf("%dth barber finish haircut\n", my_id);}return 0;}DWORD WINAPI customer_thread(void *param){int my_id;my_id = ++customer_id;printf("---------------%dth customer come\n", my_id);WaitForSingleObject(hMutex, INFINITE);if(waits<CH){waits++;printf("---------------%dth customer sits. Now totally %d customers waiting\n", my_id, waits);ReleaseSemaphore(hCustomers, 1, NULL);ResumeThread(barber_thread); /*call a barber to haircut此时customer还没离开临界区,barber即使resume也没获得控制*/ReleaseMutex(hMutex);printf("%dth customer is waiting\n", my_id);WaitForSingleObject(hBarbers, INFINITE);printf("%dth customer get ready for haircut\n", my_id);Sleep(3000);printf("%dth customer have been haircut and leave\n", my_id);}else{printf("---------------Now totally %d customers waiting.No seat. %dth customer leaves. \n",  waits, my_id);ReleaseMutex(hMutex);}return 0;}int main (){hMutex = CreateMutex(NULL, FALSE, L"mutex");hBarbers = CreateSemaphore(NULL, 0, BARBERS, L"barbers"); // barbers currently availablehCustomers = CreateSemaphore(NULL, 0, CH, L"customer"); //customers waitingHANDLE h;int *temp = new int [BARBERS];for(int i=0; i<BARBERS; ++i) {temp[i] = i+1; // barber's idh = CreateThread(NULL, 0, barber_thread, (void *)(&temp[i]), 0, NULL);}srand(time(NULL));while(1){if(rand()%4==0)h = CreateThread(NULL, 0, customer_thread, NULL, 0, NULL);if(rand()%3==0)h = CreateThread(NULL, 0, customer_thread, NULL, 0, NULL);if(rand()%2==0)h = CreateThread(NULL, 0, customer_thread, NULL, 0, NULL);Sleep(2000);}delete temp;CloseHandle(hMutex);CloseHandle(hBarbers);CloseHandle(hCustomers);CloseHandle(h);return 0;}

今天主要讨论,伪代码中的barber()里signal(barberReady)可以放在(cut hair)的后面,下面附上第二种做法。第二种输出也挺合理,但逻辑上没有第一种好
第二种,相比于第一种的不同就是,把signal(barberReady)放在(cut hair)后面,hBarber的semaphore一开始设为2。下面附上代码



DWORD WINAPI barber_thread(void *param){int my_id = *(int *)param;while(1){WaitForSingleObject(hCustomers, INFINITE);WaitForSingleObject(hMutex, INFINITE);waits--;ReleaseMutex(hMutex);printf("%dth barber starts to haircut\n", my_id);Sleep(3000);printf("%dth barber finish haircut\n", my_id);ReleaseSemaphore(hBarbers, 1, NULL);ResumeThread(customer_thread);// call a customer to haircut}return 0;}hBarbers = CreateSemaphore(NULL, BARBERS, BARBERS, L"barbers"); // barbers currently available

……
                                             
0 0
原创粉丝点击