【问题标题】:How can I solve the Sushi Bar Problem without using semaphores?如何在不使用信号量的情况下解决寿司吧问题?
【发布时间】:2019-03-08 03:03:48
【问题描述】:

问题:

此代码用于解决同步问题,称为寿司吧问题。规则如下:

想象一下有 5 个座位​​的寿司吧。如果您在有 空座,可以马上坐下。但是,如果您在所有座位时到达 吃饱了,说明大家一起吃饭,你会 坐下之前必须等待整个聚会都离开。

脚本:

这里的代码使用信号量在 C 中工作。我一直试图在没有信号量的情况下编写它,但无济于事。它不必是 C 语言,它可以是 C++ 或其他语言。

我在考虑条件变量,但我不确定如何实现它们。如果有人可以帮忙,我将不胜感激!

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdbool.h>

int eating = 0, waiting = 0;
bool must_wait = false;
sem_t block;                                                            
sem_t mutex;

void * sushiBar(void * threadID)
{
usleep(rand() % 1000);

sem_wait(&mutex);
if(must_wait){
    printf("Waits: %d seats are available. %d other people waiting.\n", 5-eating, waiting);
    waiting++;
    sem_post(&mutex);
    sem_wait(&block);
    waiting--;
}
if(eating == 4)
    printf("Last seat is taken.\n");
else{
    printf("%d seats available. Sits and eats sushi.\n", 5-eating);
}

eating++;
must_wait = (eating == 5);

if(waiting && (!must_wait))
    sem_post(&block);
else
    sem_post(&mutex);

usleep((rand() % 901) + 100);
sem_wait(&mutex);
eating--;
printf("Customer leaves: %d seats are available.\n", 5-eating);
if (eating == 0)
    must_wait = false;
if ( waiting && (!must_wait))
    sem_post(&block);
else
    sem_post(&mutex);
return 0;
}

int main(){
 int n=10,i=0,retVal=0;
 pthread_t *thread;

sem_init(&mutex, 0, 1);
sem_init(&block, 0, 0);

thread = (pthread_t *) malloc (n*sizeof(pthread_t));

for (i=0; i<n; i++){
  retVal = pthread_create(&thread[i], NULL, sushiBar, (void*)&i);
  if (retVal != 0){
    exit(EXIT_FAILURE);        
   }
}

for(i=0; i<n; i++){
    retVal = pthread_join(thread[i],NULL);
        if(retVal != 0){
           exit(EXIT_FAILURE);        
        }
 }

return 0;
}

【问题讨论】:

    标签: c++ c synchronization semaphore condition-variable


    【解决方案1】:

    我已经在 C++(basic implementation) 中使用 condition_variable 实现了这个问题。您可以将其作为起点并尝试开发您的应用程序

    #include <iostream>           
    #include <thread>             
    #include <mutex>           
    #include <condition_variable>
    
    std::mutex mtx;
    std::condition_variable cv;
    int noofseats = 0;
    bool ready = false;
    
    void enter_bar(int id) {
        std::unique_lock<std::mutex> lck(mtx);
    
        while (noofseats  >= 5)
        {
            //lock threads if seats are filled
            cv.wait(lck);
            std::cout << "User :  " << id << "waiting for seat" << std::endl;
    
        }
        std::cout << "User :  " << id << "got seat" << std::endl;
        noofseats++;
    
    }
    
    void exit_bar()
    {
        std::unique_lock<std::mutex> lck(mtx);
        noofseats--;
        if(noofseats < 5)
        {
            //would unloack other threads if seats are present
            cv.notify_all();
        }
    
    }
    
    int main()
    {
        std::thread threads[10];
        // spawn 10 threads:
        for (int i = 0; i<10; ++i)
        {
            threads[i] = std::thread(enter_bar, i);
        }
    
        //three people exit bar
        exit_bar();       
        exit_bar();
        exit_bar();
    
        for (auto& th : threads) th.join();
    
        return 0;
    }
    

    【讨论】:

    • 如果五个座位都坐满了,一个人应该等到每个人都退出。我将如何实施?还有,你在main中调用exit_bar()的地方,为什么会有三个人退出?
    • 如果人进入酒吧,则执行例程 enter_bar() 并且变量 noofseats(占用的座位数)增加,当等于 5 时,条件变量被锁定,人必须等待跨度>
    • exit_bar 在 peson 退出 bar 时执行,并且 noofsetas 小于 5 时会增加,条件变量已解锁。在上面的程序中,我刚刚预计有 10 人进入酒吧,其中 3 人将退出
    • 我的意思是当酒吧已满(5 个人在里面)并且有人来到酒吧并想要进入时,那个人必须等到所有 5 人离开酒吧。否则,如果有人来到酒吧并且没有满员(例如 4 人),他们可以进入。然后下一个人将不得不等到每个人都离开,因为酒吧现在已经满了。我将如何实现它?
    • 非常感谢您的帮助,但我仍然没有得到它。
    【解决方案2】:

    伪代码如下所示:

    // global varaible
    int seatsAtSushiBar = 5;
    
    void
    routineAtSushiBar()
    {
        grabSeatAtSushiBar();
        haveLunch();
        releaseSeatAtSushiBar();
    }
    
    void
    grabSeatAtSushiBar()
    {
        // Get exclusive lock.
        condition_mutex->lock();
            while (0 == seatsAtSushiBar) {
                // Sleep while no seat available.
                condition_mutex->wait();
                // After wakeup you must check the conditon again, 
                // to protect from spurious wakeup calls.
            }
            // Seat is available grab one for yourself.
            seatsAtSushiBar--;
        condition_mutex->unlock();
    }
    
    void
    releaseSeatAtSushiBar()
    {
        // Get exclusive lock.
        condition_mutex->lock();
            // Release the seat.
            seatsAtSushiBar++;
            if (1 == seatsAtSushiBar) {
                // Wakeup a blocking customer to grab the seat.
                condition_mutex->notify();
            }
        condition_mutex->unlock();
    }
    

    【讨论】:

      猜你喜欢
      • 2017-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多