生产者消费者模型及Linux中与条件变量相关的接口及BlockingQueue

生产者消费者模型优点

解耦

支持并发

支持忙闲不均 

条件变量

当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。

例如一个线程访问队列时,发现队列为空,它只能等待,只到其它线程将一个节点添加到队列中。这种情 况就需要用到条件变量。

条件变量可以用来定义变量或对象。

条件变量相关的接口

条件变量函数 初始化

int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict 
attr); 
参数: 
 cond:要初始化的条件变量 
 attr:NULL 

 销毁

int pthread_cond_destroy(pthread_cond_t *cond)

 等待条件满足

int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex); 
 参数: 
 cond:要在这个条件变量上等待 
 mutex:互斥量,后面详细解释 

 pthread_cond_wait细节

//临界区:

        //pthread_cond_wait   第二个参数必须为我们正在使用的互斥锁!!!

        //1.pthread_cond_wait:该函数在调用的时候,会以原子性的方式将锁释放,并将自己挂起

        //2.pthread_cond_wait:该函数在被唤醒返回的时候,会自动重新获取当时传入的锁

 唤醒等待

 int pthread_cond_broadcast(pthread_cond_t *cond); 
 int pthread_cond_signal(pthread_cond_t *cond);

 将一个线程投入一个队列中,让其在某个条件变量下等待,自动排队时,可以让其他线程唤醒指定线程。

一次唤醒一个线程

//一次唤醒一个线程
pthread_cond_wait(&cond,&mutex);

一次唤醒批线程 

//一次唤醒批线程
pthread_cond_broadcast(&cond,&mutex);
#include<iostream>
#include<cstdio>
#include<string>
#include<unistd.h>
#include<pthread.h>

using namespace std;

int tickets=1000;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
void* start_routine(void* args)
{
    string name =static_cast<const char*>(args);
    while(true)
    {
        pthread_mutex_lock(&mutex);
        //一次唤醒一个线程
        //pthread_cond_wait(&cond,&mutex);
        //一次唤醒批线程
        pthread_cond_broadcast(&cond,&mutex);
        cout<<name<<" -> "<<tickets<<endl;
        tickets--;
        pthread_mutex_unlock(&mutex);
    }
}
int main()
{
    //创建一批线程
    pthread_t t[5];
    for(int i=0;i<5;i++)
    {
        char* name =new char[64];
        snprintf(name,64,"thread: %d",i+1);
        pthread_create(t+i,nullptr,start_routine,name);
    }
    //通过条件变量控制线程执行
    while(true)
    {
        sleep(1);
        pthread_cond_signal(&cond);
        cout<<"main thread wakeup one thread..."<<endl;
    }
    for(int i=0;i<5;i++)
    {
        pthread_join(t[i],nullptr);
    }
    return 0;
}

基于BlockingQueue的生产者消费者模型

 

 

#pragma once

#include<iostream>
#include<queue>
#include<pthread.h>
#include<unistd.h>

using namespace std;
static const int gmaxcap=5;
template<class T>
class BlockQueue
{
public:
    
    BlockQueue(const int& maxcap=gmaxcap)
        :_maxcap(maxcap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_pcond,nullptr);
        pthread_cond_init(&_ccond,nullptr);
    }
    void push(const T& in)//输入型参数,const &
    {
        pthread_mutex_lock(&_mutex);
        //1.判断
        while(is_full())//防止向队列中多push内容->提高代码健壮性
        {//生产条件不满足无法生产,需要生产者等待
        //临界区:
        //pthread_cond_wait   第二个参数必须为我们正在使用的互斥锁!!!
        //1.pthread_cond_wait:该函数在调用的时候,会以原子性的方式将锁释放,并将自己挂起
        //2.pthread_cond_wait:该函数在被唤醒返回的时候,会自动重新获取当时传入的锁
            pthread_cond_wait(&_pcond,&_mutex);
        }
        _q.push(in);
        //pthread_cond_signal即可在临界区内也可在临界区外
        pthread_cond_signal(&_ccond);
        pthread_mutex_unlock(&_mutex);

    }
    void pop(T* out)//输出型参数:*, // 输入输出型:&
    {
        pthread_mutex_lock(&_mutex);
        if(is_empty())
        {
            pthread_cond_wait(&_ccond,&_mutex);
        }
        *out=_q.front();
        _q.pop();
        pthread_cond_signal(&_pcond);
        pthread_mutex_unlock(&_mutex);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_pcond);
        pthread_cond_destroy(&_ccond);
    }
private:
    bool is_empty() 
    {
        return _q.empty();
    }
    bool is_full()
    {
        return _q.size()==_maxcap;
    }
    queue<T> _q;
    int _maxcap;//队列中元素的上限
    pthread_mutex_t _mutex;
    pthread_cond_t _pcond;//生产者对应的条件变量
    pthread_cond_t _ccond;//消费者对应的条件变量
};

 往阻塞队列中放内容:

#include"BlockQueue.hpp"
#include<time.h>
#include<sys/types.h>

void *consumer(void* bq_)
{
    BlockQueue<int>* bq=static_cast<BlockQueue<int>*>(bq_);
    while(true)
    {
        //消费活动
        int data;
        bq->pop(&data);
        cout<<"消费数据: "<<data<<endl;
        sleep(1);
    }
    return nullptr;
}
void* productor(void *bq_)
{
    BlockQueue<int>* bq=static_cast<BlockQueue<int>*>(bq_);

    while(true)
    {
        //生产活动-x先用随机数构建数据
        int data=rand()%10+1;
        bq->push(data);
        cout<<"生产数据: "<<data<<endl;
        sleep(1);
    }
    return nullptr;
}
int main()
{
    srand((unsigned long)time(nullptr));
    BlockQueue<int>* bq=new BlockQueue<int>();

    pthread_t c,p;
    pthread_create(&c,nullptr,consumer,bq);
    pthread_create(&p,nullptr,productor,bq);
    
    pthread_join(c,nullptr);
    pthread_join(p,nullptr);
    delete bq;
    return 0;
}
BlockQueue<int>* bq=new BlockQueue<int>();

优化:int有点low可以将int换为其他。 

 生产数据: 10
消费数据: 10
生产数据: 1
消费数据: 1
生产数据: 1
消费数据: 1
生产数据: 3
消费数据: 3
生产数据: 7
消费数据: 7

sleep函数的头文件 

sleep函数的头文件_sleep函数头文件-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/modi000/article/details/117064651

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值