Sleeping Barber algorithm (with multiple barbers)

匿名 (未验证) 提交于 2019-12-03 02:59:02

问题:

The Sleeping Barber Problem is a classical synchronization problem that many of you may be familiar with or at least heard of.

It's based on the premise that a barber (a thread) sleeps when there are no customers (each customer is a thread) in the waiting room (which is a semaphore). If there is someone, he cuts his hair (symbolizing some processing) and the costumer leaves. If, then, there is no one in the waiting room, the barber goes to sleep. When another customer arrives, he then must wake up the barber.


I have made a implementation of this using the following basic-idea

(although the actual code is in C, I wrote the following pseudo-code without much care for the syntax for sake of problem-understading, only using sem_wait and sem_post1 for smoother reading)

Semaphore Customers = 0; Semaphore Barber = 0; Mutex accessSeats = 1; int NumberOfFreeSeats = N;   Barber {     while(1) {         sem_wait(Customers); // waits for a customer (sleeps)         sem_wait(accessSeats); // mutex to protect the number of available seats         NumberOfFreeSeats++; // a chair gets free         sem_post(Barber); // bring customer for haircut         sem_post(accessSeats); // release the mutex on the chair         // barber is cutting hair     } }  Customer {     while(1) {         sem_wait(accessSeats); // protects seats so only 1 thread tries to sit in a chair if that's the case         if(NumberOfFreeSeats > 0) {             NumberOfFreeSeats--; // sitting down             sem_post(Customers); // notify the barber             sem_post(accessSeats); // release the lock             sem_wait(Barber); // wait in the waiting room if barber is busy             // customer is having hair cut         } else {             sem_post(accessSeats); // release the lock             // customer leaves         }    } } 

However, now that I'll implement this problem with multiple barbers, my head got stuck. I went on Wikipedia to see if I could find something about it, but the only thing that I found there was this

A multiple sleeping barbers problem has the additional complexity of coordinating several barbers among the waiting customers.

and I couldn't figure this out by myself 2.

What changes would I have to do in my code? Where would I need an extra semaphore here?

1sem_wait() locks the semaphore. sem_post() unlocks it
2Disclaimer: Although I have asked this in programmers.stackexchange aswell, I did not have reached a desired answer and my question still persists.

回答1:

The code as written will manage any number of barbers without any additional semaphores. Simply start a Barber{} thread for each barber in the shop.

The problem referenced in the Wikipedia remark is this: just because you have M barbers in the "barber is cutting hair" state and M customers in the "customer is having hair cut" state, there's no guarantee that some barber isn't trying to clip more than one customer, or that some customer doesn't have several barbers in his hair.

In other words, once the proper number of customers have been allowed into the cutting room, how do the barbers and customers pair off? You can no longer say "barber is cutting hair" and "customer is having hair cut"; you have to say "barber is cutting hair of customer C" and "customer is having hair cut by barber B".

// Assumptions about the meaning of 'haircut': // each thread has a unique PID // each thread can get its own PID via system.info.PID // a barber uses a customer's PID to cut that custmer's hair // a customer uses a barber's PID to get his hair cut by that barber // Assumptions about the operating environment: // a semaphore releases threads in the order that they were queued  Semaphore Customers = 0; Semaphore Barbers = 0; Mutex AccessSeats = 1; int NumberOfFreeSeats = N; int SeatPocket[N];  // (or 'PID SeatPocket[N];' if PID is a data type) int SitHereNext = 0; int ServeMeNext = 0;  // main program must start a copy of this thread for each barber in the shop Barber {     int mynext, C;     while(1) {         sem_wait(Barbers);  // join queue of sleeping barbers         sem_wait(AccessSeats);  // mutex to protect seat changes         ServeMeNext = (ServeMeNext++) mod N;  // select next customer         mynext = ServeMeNext;         C = SeatPocket[mynext];  // get selected customer's PID         SeatPocket[mynext] = system.info.PID;  // leave own PID for customer         sem_post(AccessSeats);  // release the seat change mutex         sem_post(Customers);  // wake up selected customer         //         // barber is cutting hair of customer 'C'         //     } }  // main program must start a copy of this thread at random intervals // to represent the arrival of a continual stream of customers Customer {     int myseat, B;     sem_wait(AccessSeats);  // mutex to protect seat changes     if(NumberOfFreeSeats > 0) {         NumberOfFreeSeats--;  // sit down in one of the seats         SitHereNext = (SitHereNext++) mod N;         myseat = SitHereNext;         SeatPocket[myseat] = system.info.PID;         sem_post(AccessSeats);  // release the seat change mutex         sem_post(Barbers);  // wake up one barber         sem_wait(Customers);  // join queue of sleeping customers         sem_wait(AccessSeats);  // mutex to protect seat changes         B = SeatPocket[myseat];  // barber replaced my PID with his own         NumberOfFreeSeats++;  // stand up         sem_post(AccessSeats);  // release the seat change mutex         //         // customer is having hair cut by barber 'B'         //     } else {         sem_post(AccessSeats);  // release the seat change mutex         // customer leaves without haircut     }     system.thread.exit;  // (or signal main program to kill this thread) } 


回答2:

This code is written by me with slight modifications from the algorithm defined by Breveleri which simulates the Multiple Sleeping Barber problem quite efficiently. I had written it for simulation purpose for my OS Assignment. I would like to get ay suggestions from your side. I'm using "declarations.h", "SleepingBarber.c" and a "makefile" for a better coding structure.

declaration.h

#include <unistd.h>          //Provides API for POSIX(or UNIX) OS for system calls #include <stdio.h>           //Standard I/O Routines #include <stdlib.h>          //For exit() and rand() #include <pthread.h>         //Threading APIs #include <semaphore.h>       //Semaphore APIs #define MAX_CHAIRS 10        //No. of chairs in waiting room #define CUT_TIME 1           //Hair Cutting Time 1 second #define NUM_BARB 2           //No. of barbers #define MAX_CUST 30          //Maximum no. of customers for simulation  sem_t customers;                 //Semaphore sem_t barbers;                   //Semaphore sem_t mutex;                     //Semaphore for providing mutially exclusive access int numberOfFreeSeats = MAX_CHAIRS;   //Counter for Vacant seats in waiting room int seatPocket[MAX_CHAIRS];           //To exchange pid between customer and barber int sitHereNext = 0;                  //Index for next legitimate seat int serveMeNext = 0;                  //Index to choose a candidate for cutting hair static int count = 0;                 //Counter of No. of customers void barberThread(void *tmp);         //Thread Function void customerThread(void *tmp);       //Thread Function void wait();                          //Randomized delay function 

SleepingBarber.c

#include "declarations.h"  int main() {        pthread_t barber[NUM_BARB],customer[MAX_CUST]; //Thread declaration     int i,status=0;     /*Semaphore initialization*/     sem_init(&customers,0,0);     sem_init(&barbers,0,0);     sem_init(&mutex,0,1);        /*Barber thread initialization*/     printf("!!Barber Shop Opens!!\n");     for(i=0;i<NUM_BARB;i++)                     //Creation of 2 Barber Threads     {           status=pthread_create(&barber[i],NULL,(void *)barberThread,(void*)&i);        sleep(1);        if(status!=0)           perror("No Barber Present... Sorry!!\n");     }     /*Customer thread initialization*/     for(i=0;i<MAX_CUST;i++)                     //Creation of Customer Threads     {           status=pthread_create(&customer[i],NULL,(void *)customerThread,(void*)&i);        wait();                   //Create customers in random interval        if(status!=0)            perror("No Customers Yet!!!\n");     }        for(i=0;i<MAX_CUST;i++)        //Waiting till all customers are dealt with         pthread_join(customer[i],NULL);     printf("!!Barber Shop Closes!!\n");     exit(EXIT_SUCCESS);  //Exit abandoning infinite loop of barber thread }  void customerThread(void *tmp)  /*Customer Process*/ {        int mySeat, B;     sem_wait(&mutex);  //Lock mutex to protect seat changes     count++;           //Arrival of customer     printf("Customer-%d[Id:%d] Entered Shop. ",count,pthread_self());     if(numberOfFreeSeats > 0)      {         --numberOfFreeSeats;           //Sit on chairs on waiting room         printf("Customer-%d Sits In Waiting Room.\n",count);         sitHereNext = (++sitHereNext) % MAX_CHAIRS;  //Choose a vacant chair to sit         mySeat = sitHereNext;         seatPocket[mySeat] = count;         sem_post(&mutex);                  //Release the seat change mutex         sem_post(&barbers);                //Wake up one barber         sem_wait(&customers);              //Join queue of sleeping customers         sem_wait(&mutex);                  //Lock mutex to protect seat changes           B = seatPocket[mySeat];    //Barber replaces customer PID with his own PID           numberOfFreeSeats++;             //Stand Up and Go to Barber Room         sem_post(&mutex);                        //Release the seat change mutex                 /*Customer is having hair cut by barber 'B'*/     }      else      {        sem_post(&mutex);  //Release the mutex and customer leaves without haircut        printf("Customer-%d Finds No Seat & Leaves.\n",count);     }     pthread_exit(0); }  void barberThread(void *tmp)        /*Barber Process*/ {        int index = *(int *)(tmp);           int myNext, C;     printf("Barber-%d[Id:%d] Joins Shop. ",index,pthread_self());     while(1)            /*Infinite loop*/        {            printf("Barber-%d Gone To Sleep.\n",index);         sem_wait(&barbers);          //Join queue of sleeping barbers         sem_wait(&mutex);            //Lock mutex to protect seat changes           serveMeNext = (++serveMeNext) % MAX_CHAIRS;  //Select next customer           myNext = serveMeNext;           C = seatPocket[myNext];                  //Get selected customer's PID           seatPocket[myNext] = pthread_self();     //Leave own PID for customer         sem_post(&mutex);         sem_post(&customers);         //Call selected customer                 /*Barber is cutting hair of customer 'C'*/         printf("Barber-%d Wakes Up & Is Cutting Hair Of Customer-%d.\n",index,C);         sleep(CUT_TIME);         printf("Barber-%d Finishes. ",index);     } }  void wait()     /*Generates random number between 50000 to 250000*/ {      int x = rand() % (250000 - 50000 + 1) + 50000;       srand(time(NULL));      usleep(x);     //usleep halts execution in specified miliseconds } 

makefile

all:    SleepingBarber SleepingBarber: SleepingBarber.o     gcc -pthread -o SleepingBarber SleepingBarber.o SleepingBarber.o: SleepingBarber.c declarations.h     gcc -c SleepingBarber.c clean:     rm -f *.o SleepingBarber 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!