关于Linux操作系统

嗜睡的理发师问题:一个理发店由一个有N张沙发的等候室和一个放有一张理发椅的理发室组成。没有顾客要理发时,理发师便去睡觉。当一个顾客走进理发店时,如果所有的沙发都已经被占用,他便离开理发店;否则,如果理发师正在为其他顾客理发,则该顾客就找一张空沙发坐下等待;如果理发师因无顾客正在睡觉,则由新到的顾客唤醒理发师为其理发。在理发完成后,顾客必须付费,直到理发师收费后才能离开理发店。帮帮忙,用信号量实习这个同步问题。

实现上面的效果,可以使用是“生产者-消费者-仓储”模型,需要实现以下几点:
1、顾客仅仅在座位未满时候入座,座位满了满则停止入店。
2、理发师仅仅在座位有顾客时候才能消费,座位空则等待。
3、当理发师发现座位没顾客可服务时候会通知顾客进店落座。
4、顾客在落座后,也需要通知睡觉的理发师来服务。
具体实现代码如下:
第一个是.hpp代码:

#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include<pthread.h>
using namespace std;

namespace ns_cq
{
    pthread_mutex_t p_mtx;
    pthread_mutex_t c_mtx;

    const int default_cap = 10;
    template <class T>
    class CircularQueue
    {
    private:
        int _cap;
        vector<T> _circul_queue;
        //顾客关心空位置的资源
        sem_t _blank_sem;
        //理发师关心位置有顾客的资源
        sem_t _data_sem;

        //用vector模拟环形队列
        int _c_step;
        int _p_step;

    public:
        CircularQueue(int cap = default_cap)
            : _cap(cap), _circul_queue(cap)
        {
            //顾客信号量初始化,初始时顾客能申请的信号量为10,因为有10个空位置
            sem_init(&_blank_sem, 0, _cap);
            //理发师信号量初始化,初始时理发师申请到的信号量为0,因为没有顾客坐位置
            sem_init(&_data_sem, 0, 0);
            _c_step = 0;
            _p_step = 0;

            pthread_mutex_init(&p_mtx, nullptr);
            pthread_mutex_init(&c_mtx, nullptr);
        }

        ~CircularQueue()
        {
            //信号量销毁
            sem_destroy(&_blank_sem);
            sem_destroy(&_data_sem);
            pthread_mutex_destroy(&p_mtx);
            pthread_mutex_destroy(&c_mtx);
        }

    public:
        void Push(const T &in)
        {
            //客户申请信号量(P操作)  相当于空座位的计数器--
            sem_wait(&_blank_sem);

            //把锁加在申请信号量后,能让多个线程并发申请信号量,然后再竞争锁,省去了单独申请信号量的时间,效率提高
            pthread_mutex_lock(&p_mtx);

            _circul_queue[_p_step] = in;

            //客户做到空座位后,更新已做人座位的下标
            _p_step++;
            _p_step %= _cap;

            pthread_mutex_unlock(&p_mtx);

            //释放信号量(V操作)        相当于有客户坐的座位的计数器++
            sem_post(&_data_sem);
        }

        void Pop(T *out)
        {
            //理发师申请信号量(P操作)  相当于有客户坐的座位的计数器--
            sem_wait(&_data_sem);

            pthread_mutex_lock(&c_mtx);

            *out = _circul_queue[_c_step];

            _c_step++;
            _c_step %= _cap;
            pthread_mutex_unlock(&c_mtx);

            //释放信号量(V操作)        相当于空座位的计数器++
            sem_post(&_blank_sem);
        }
    };
}

第二个是.cpp代码:

#include <iostream>
using namespace std;
#include "Circular_queue.hpp"
using namespace ns_cq;
using namespace ns_task;
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include "task.hpp"

void *Consumer(void *args)
{
    CircularQueue<Task> *cq = (CircularQueue<Task> *)args;
    while (true)
    {
        // sleep(1);
        Task t;
        cq->Pop(&t);
        t.Run();
        sleep(1);
    }
}

void *Producter(void *args)
{
    CircularQueue<Task> *cq = (CircularQueue<Task> *)args;
    while (true)
    {
        sleep(1);
        cout << " 有一个顾客入店落座了!快醒醒" << endl;
        cq->Push(t);
    }
}

int main()
{
    srand((long long)time(nullptr));
    pthread_t c0, c1, c2, c3, p0, p1, p2, p3;
    CircularQueue<Task> *cq = new CircularQueue<Task>();

    pthread_create(&c0, nullptr, Consumer, (void *)cq);
    pthread_create(&c1, nullptr, Consumer, (void *)cq);
    pthread_create(&c2, nullptr, Consumer, (void *)cq);
    pthread_create(&c3, nullptr, Consumer, (void *)cq);
    pthread_create(&p0, nullptr, Producter, (void *)cq);
    pthread_create(&p1, nullptr, Producter, (void *)cq);
    pthread_create(&p2, nullptr, Producter, (void *)cq);
    pthread_create(&p3, nullptr, Producter, (void *)cq);

    pthread_join(c0, nullptr);
    pthread_join(c1, nullptr);
    pthread_join(c2, nullptr);
    pthread_join(c3, nullptr);
    pthread_join(p0, nullptr);
    pthread_join(p1, nullptr);
    pthread_join(p2, nullptr);
    pthread_join(p3, nullptr);
    return 0;
}