Bootstrap

【Linux:生产消费模型】

目录

条件变量的相关接口:

条件变量理解:

生产消费模型:

理解生产者消费者模型特点:

消费者&&生产者接口:

生产者:​编辑

消费者: 

伪唤醒:

生产消费模型内部封装:


条件变量的相关接口:

  •  int pthread_cond_destroy(pthread_cond_t *cond);
  •  int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
  •  pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  •   int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);//线程等待,线程首先参与锁的竞争,得到锁后才会返回

  • int pthread_cond_broadcast(pthread_cond_t *cond);//唤醒多个线程
  •  int pthread_cond_signal(pthread_cond_t *cond);//唤醒一个线程

条件变量理解:

  • 上图中两个人同时都需要共享资源中的数据,但资源是有限的,男孩拿了资源,那么女孩需要等资源存在再进行拿去,为了避免女孩白跑,三者之间存在一个消息,通知资源是否已到位,而这个消息就是条件变量。

生产消费模型:

以现实生活中的工厂举例:

  • 工厂生产大批的商品运往各大超市,便利店等地方
  • 消费者从超市、便利店等地方购买所需要的物品,而不是从供应商中拿去
  • 超市就是工厂与消费者二者之间的一个传递关系

锁和条件变量即可实现以上三种关系


理解生产者消费者模型特点:

  1. 一个交易场所
  2. 两种角色(生产线程,消费线程)
  3. 三种关系
  • 生产&&生产
  • 消费&&消费
  • 生产&&消费 

消费者&&生产者接口:

生产者:

消费者: 

伪唤醒:

情况:一个生产者只生产唯一的产品,但消费者有两位。

  • 生产者生产完后,通知消费者消费,一次性唤醒多个线程
  • 但产品是唯一的
  • 多个线程同时唤醒时,都会参与锁的竞争
  • 一个线程拿取到锁,wait返回,但其他线程开始在锁的位置等待
  • 等上一个线程释放完锁后,直接拿取锁,不会走判断队列是否为空的代码。
  • 线程进入空队列后,代码就出现了问题

总结:伪唤醒就是添加未被满足,但线程被异常唤醒叫做伪唤醒

生产消费模型内部封装:

const static int defaultcap=3;

template <typename T>
class Blockqueue
{
    private:
    bool Isfull()
    {
        return _block_queue.size()==_max_cap;
     }
    bool IsEmpty()
    {
        return _block_queue.empty();
    }

    public:
    Blockqueue(int cap=defaultcap):_max_cap(cap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_p_cond,nullptr);
        pthread_cond_init(&_c_cond,nullptr);

    }
    void Pop(T *out)
    {
        pthread_mutex_lock(&_mutex);
        while(IsEmpty())
        {
            pthread_cond_wait(&_c_cond,&_mutex);

        }
        *out=_block_queue.front();
        _block_queue.pop();
        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_p_cond);//唤醒生产者生产


    }

    void enqueue(const T&in)
    {
        pthread_mutex_lock(&_mutex);
        //判断队列是否满
        while(Isfull())
        {
            //加锁后,线程判断队列是否已满
            //队列满了,线程就会阻塞的等待
            //等待的同时,该线程会释放锁
            //当该函数返回之前,线程首先需要参与锁的竞争,重新加上锁
            pthread_cond_wait(&_p_cond,&_mutex);
        }
        //没有满||队列为空,生产者生产
        _block_queue.push(in);
        pthread_mutex_unlock(&_mutex);
        //对于线程的唤醒位置是否需要在释放锁的前后原因:
        //1.放在释放锁的前面: 生产者唤醒消费者线程,消费者线程被唤醒
        //                    生产者释放锁,消费者竞争锁,拿取到锁,开始消费
        //2.放在释放锁的后面: 生产者释放锁后同时又开始参与锁的竞争
        //                    唤醒消费线程,消费者线程参与锁的竞争
        //                    由于队列已满,生产者线程等待同时释放锁,消费者线程拿取到锁
        pthread_cond_signal(&_c_cond);//唤醒消费者消费
    }
    ~Blockqueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_p_cond);
        pthread_cond_destroy(&_c_cond);

    }
    private:
    std::queue<T> _block_queue;
    int _max_cap;
    pthread_mutex_t _mutex;
    //生产者
    pthread_cond_t _p_cond;
    //消费者
    pthread_cond_t _c_cond;

};

;