Linux多线程 | 生产者消费者模型

生产者消费者模型:是一种典型的设计模式。 他的应用场景是针对大量的数据产生与处理的场景

组成

一个场所:线程安全的数据队列
两种角色:生产者与消费者
三种关系

        生产者与生产者关系:互斥
        消费者与消费者关系:互斥
        生产者与消费者关系:同步+互斥

为什么要使用生产者消费者模型

生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的

生产者消费者模型优点

解耦合、支持忙闲不均,支持并发

 

基于阻塞队列的生产者消费者模型

#define CAPCITY 5
class BlockQueue
{
public:
    BlockQueue(int cap = CAPCITY) : _capcity(cap)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond_cus, nullptr);
        pthread_cond_init(&_cond_pro, nullptr);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond_pro);
        pthread_cond_destroy(&_cond_cus);
    }

    void push(const int &val)
    {
        pthread_mutex_lock(&_mutex);

        //队列满了 等待 消费者唤醒
        while (_queue.size() == CAPCITY)
            pthread_cond_wait(&_cond_pro, &_mutex);
        _queue.push(val);

        //唤醒消费者进行消费
        pthread_cond_signal(&_cond_cus);
        pthread_mutex_unlock(&_mutex);
    }

    void pop(int *data)
    {
        pthread_mutex_lock(&_mutex);
        while (_queue.empty())
            pthread_cond_wait(&_cond_cus, &_mutex);
        *data = _queue.front();
        _queue.pop();

        pthread_cond_signal(&_cond_pro);
        pthread_mutex_unlock(&_mutex);
    }

private:
    queue<int> _queue; //阻塞队列
    int _capcity;      //队列容量
    pthread_mutex_t _mutex;
    pthread_cond_t _cond_pro; //生产者条件变量
    pthread_cond_t _cond_cus; //消费者条件变量
};

void *customer(void *arg)
{
    BlockQueue *q = (BlockQueue *)arg;
    int data;
    while (1)
    {
        q->pop(&data);
        printf("消费者:%p消费数据%d\n", pthread_self(), data);
        //usleep(1);
    }
    return NULL;
}

void *product(void *arg)
{
    BlockQueue *q = (BlockQueue *)arg;
    int data = 0;
    while (1)
    {
        q->push(data);
        printf("生产者:%p生产数据%d\n", pthread_self(), data++);
        //usleep(1);
    }

    return NULL;
}

int main()
{

    BlockQueue q;
    int ret;
    pthread_t cid[4], pid[4];
    for (int i = 0; i < 4; ++i)
    {
        ret = pthread_create(&cid[i], nullptr, customer, &q);
        if (ret != 0)
            return -1;
        ret = pthread_create(&pid[i], nullptr, product, &q);
        if (ret != 0)
            return -1;
    }

    for (int i = 0; i < 4; ++i)
    {
        pthread_join(cid[i], nullptr);
        pthread_join(pid[i], nullptr);
    }
}

基于环形队列的生产消费模型

#define MAX_QUEUE 5
class RingQueue
{
public:
    RingQueue(int cap = MAX_QUEUE)
        : _capacity(cap), _pwrite(0), _pread(0), _array(cap)
    {
        sem_init(&_sem_data, 0, 0);
        sem_init(&_sem_idle, 0, cap);
        sem_init(&_sem_lock, 0, 1);
    }
    ~RingQueue()
    {
        sem_destroy(&_sem_data);
        sem_destroy(&_sem_idle);
        sem_destroy(&_sem_lock);
    }
    void push(const int &val)
    {
        sem_wait(&_sem_idle);
        
        //加锁
        sem_wait(&_sem_lock);
        _array[_pwrite] = val;
        _pwrite = (_pwrite + 1) % _capacity;
        //解锁
        sem_post(&_sem_lock);

        sem_post(&_sem_data);
    }

    void pop(int *data)
    {
        sem_wait(&_sem_data);

        sem_wait(&_sem_lock);
        *data = _array[_pread];
        _pread = (_pread + 1) % _capacity;
        sem_post(&_sem_lock);

        sem_post(&_sem_idle);
    }

private:
    int _capacity; //循环队列的容量
    int _pwrite;   //读指针
    int _pread;    //写指针
    std::vector<int> _array;

    sem_t _sem_data; //数据节点计数
    sem_t _sem_idle; //空闲节点计数
    sem_t _sem_lock; //用于实现互斥
};
void *product(void *arg)
{
    RingQueue *q = (RingQueue *)arg;
    int val = 1;
    while (1)
    {
        q->push(val);
        printf("push data: %d\n", val++);
    }
    return nullptr;
}
void *customer(void *arg)
{
    RingQueue *q = (RingQueue *)arg;
    int val;
    while (1)
    {
        q->pop(&val);
        printf("pop data: %d\n", val);
    }
    return nullptr;
}
int main()
{
    RingQueue q;
    pthread_t pid[4], cid[4];
    for (int i = 0; i < 4; ++i)
    {
        pthread_create(&pid[i], nullptr, product, &q);
        pthread_create(&cid[i], nullptr, customer, &q);
    }

    for (int i = 0; i < 4; ++i)
    {
        pthread_join(pid[0], nullptr);
        pthread_join(cid[0], nullptr);
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值