【问题标题】:Sleeping Barber algorithm (with multiple barbers)睡眠理发师算法(有多个理发师)
【发布时间】:2013-10-30 19:48:52
【问题描述】:

Sleeping Barber Problem 是一个经典的同步问题,你们中的许多人可能都熟悉或至少听说过。

这是基于理发师(一个线程)在没有顾客(每个顾客是一个线程)在等候室(这是一个信号量)。如果有人,他会剪掉头发(象征着一些处理),然后顾客离开。如果等候室里没有人,理发师就去睡觉。当另一位顾客到达时,他必须叫醒理发师。


我已经使用以下基本思想实现了这一点

(虽然实际代码在C 中,但我编写了以下伪代码,为了理解问题,我没有过多注意语法,仅使用sem_waitsem_post1 阅读更流畅)

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
        }
   }
}

但是,既然我要使用多个理发师来解决这个问题,我的头就卡住了。我去维基百科看看能不能找到关于它的东西,但我发现的唯一东西就是这个

多个睡着的理发师问题具有额外的复杂性,需要在等待的顾客之间协调多个理发师。

而我自己无法解决这个问题2

我必须对我的代码进行哪些更改?我在哪里需要额外的信号量?

1sem_wait() 锁定信号量。 sem_post() 解锁它
2免责声明:虽然我也曾在programmers.stackexchange 中提出过这个问题,但我没有得到想要的答案,我的问题仍然存在。

【问题讨论】:

  • 也许您可以将其与生产者/消费者问题混为一谈。每当客户端到达时,它就会被分配到一个受信号量保护的 FIFO 结构中。理发师将从 FIFO 中“消费”客户。稍后我会尝试看一下代码......
  • Here 是我见过的关于生产者/消费者队列的最佳解释。它是用 C# 编写的,但你可能很幸运能将它翻译成 C。
  • 理发师和顾客之间协调的确切细节将在很大程度上取决于您所说的“理发”。

标签: multithreading algorithm


【解决方案1】:

编写的代码将管理任意数量的理发师,无需任何额外的信号量。只需为店内的每个理发师创建一个 Barber{} 线程。{}

维基百科评论中提到的问题是这样的:仅仅因为您有 M 位理发师处于“理发师正在理发”状态,而 M 位客户处于“客户正在理发”状态,并不能保证某些理发师没有。 t 试图为多个顾客剪头发,或者某些顾客的头发上没有几个理发师。

换句话说,一旦允许适当数量的顾客进入剪裁室,理发师和顾客如何配对?你不能再说“理发师在剪头发”和“顾客在剪头发”;您必须说“理发师正在为客户 C 剪头发”和“客户正在由理发师 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】:

    这段代码是我编写的,对 Breveleri 定义的算法稍作修改,该算法非常有效地模拟了 Multiple Sleeping Barber 问题。我写它是为了模拟我的操作系统分配。我想从你身边得到任何建议。我正在使用“declarations.h”、“SleepingBarber.c”和“makefile”来获得更好的编码结构。

    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
    }
    

    制作文件

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多