基于BlockQueue的生产消费模型及Linux中的信号量

 基于BlockQueue的生产消费模型

Task.hpp

#pragma once

#include<cstdio>
#include<iostream>
#include<string>
#include<functional>

using namespace std;
class CalTask
{
    using func_t=function<int(int,int,char)>;
    //typedef function<int(int,int)> func_t;
public:
    CalTask()
    {}
    CalTask(int x,int y,char op,func_t func):_x(x),_y(y),_op(op),_callback(func)
    {}
    string operator()()
    {
        int result=_callback(_x,_y,_op);
        //构建结构字符串
        char buffer[1024];
        snprintf(buffer,sizeof buffer,"%d %c %d = %d ",_x,_op,_y,result);
        return buffer;
    }
    string toTaskString()
    {
        char buffer[1024];
        snprintf(buffer,sizeof buffer,"%d %c %d = ? ",_x,_op,_y);
        return buffer;
    }
private:
    int _x;
    int _y;
    char _op;
    func_t _callback;
};

int mymath(int x,int y,char op)
{
    int result=0;
    switch(op)
    {
        case '+':
            result=x+y;
        break;
        case '-':
            result=x-y;
        break;
        case '*':
            result=x*y;
        break;
        case '/':
        {
            if(y==0)
            {
                cerr<<"div zero error!!!"<<endl;
                result=-1;
            }
            else
                result=x/y;
        }
        break;
        case '%':
        {
            if(y==0)
            {
                cerr<<"mod zero error!!!"<<endl;
                result=-1;
            }
            else
                result=x%y;
        }          
        break;
        default:
        break;
    }
    return result;
}
class SaveTask
{
    typedef function<void(const string&)> func_t;
public:
    SaveTask()
    {}
    SaveTask(const string &message,func_t func)
    :_message(message),_func(func)
    {}
    void operator()()
    {
        _func(_message);
    }
private:
    string _message;
    func_t _func;
};
void Save(const string& message)
{
    const string target="./log.txt";
    FILE* fp=fopen(target.c_str(),"a+");
    if(!fp)
    {
        cerr<<" fopen error "<<endl;
        return;
    } 
    fputs(message.c_str(),fp);
    fputs("\n",fp);
    
    fclose(fp);
}

Block.hpp

#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);
        while(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;//消费者对应的条件变量
}; 

Main.cc

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

const string oper="+-*/%";

template<class C,class S>
class BlockQueues
{
public:
    BlockQueue<C> *c_bq;
    BlockQueue<S> *s_bq;
};
void* productor(void *bqs_)
{
    //BlockQueue<Task>* bq=static_cast<BlockQueue<Task>*>(bq_);
    BlockQueue<CalTask>* bq= (static_cast<BlockQueues<CalTask,SaveTask>*>(bqs_))->c_bq;

    while(true)
    {
        //生产活动-x先用随机数构建数据
        int x=rand()%10+1;
        int y=rand()%5;
        int operCode=rand()%oper.size();
        CalTask t(x,y,oper[operCode],mymath);
        bq->push(t);
        cout<<"productor thread,生产数据: "<<t.toTaskString()<<endl;
        sleep(1);
    }
    return nullptr;
}
void *consumer(void* bqs_)
{
    //BlockQueue<Task>* bq=static_cast<BlockQueue<Task>*>(bq_);
    BlockQueue<CalTask>* bq= (static_cast<BlockQueues<CalTask,SaveTask>*>(bqs_))->c_bq;
    BlockQueue<SaveTask>* save_bq= (static_cast<BlockQueues<CalTask,SaveTask>*>(bqs_))->s_bq;
    
    while(true)
    {
        //消费活动
        CalTask t;
        bq->pop(&t);
        string result=t();
        cout<<"消费任务: "<<result<<endl;
        
        // SaveTask save(result,Save);
        // save_bq->push(save);
        // cout<<"consumer thread,推送保存任务完成..."<<endl;

    }
    return nullptr;
}

void* saver(void* bqs_)
{
    BlockQueue<SaveTask>* save_bq= (static_cast<BlockQueues<CalTask,SaveTask>*>(bqs_))->s_bq;

    while(true)
    {
        SaveTask t;
        save_bq->pop(&t);
        t();
        cout<<"保存任务完成..."<<endl;
    }
}
int main()
{
    srand((unsigned long)time(nullptr));
    BlockQueues<CalTask,SaveTask> bqs;
    bqs.c_bq=new BlockQueue<CalTask>();
    bqs.s_bq=new BlockQueue<SaveTask>();

    pthread_t c,p,s;
    pthread_create(&c,nullptr,consumer,&bqs);
    pthread_create(&p,nullptr,productor,&bqs);
    // pthread_create(&s,nullptr,saver,&bqs);
    
    pthread_join(c,nullptr);
    pthread_join(p,nullptr);
    // pthread_join(s,nullptr);
    
    delete bqs.c_bq;
    delete bqs.s_bq;
    return 0;
}

POSIX信号量

POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于 线程间同步。 

        pthread_mutex_lock(&_mutex);
        while(is_empty())
        {
            pthread_cond_wait(&_ccond,&_mutex);
        }
        *out=_q.front();
        _q.pop();
        pthread_cond_signal(&_pcond);
        pthread_mutex_unlock(&_mutex);

该段代码涉及到对临界资源的访问:

1.一个线程,在操作临界资源的时候,临界资源必须是满足条件的!!!

2.公共资源是否满足生产或消费条件【我们在访问之前无法得知】

3.只能先加锁,在检测,在操作,在解锁

只要对资源进行整体加锁,就默认对资源整体使用,但是实际情况可能是一份公共资源允许同时访问不同区域。

什么事信号量???

a.信号量本质是一个计数器。->用来衡量有多少临界资源。

b.只要拥有信号量,就在未来一定能够拥有临界资源的一部分。

申请信号量的本质:对临界资源中特定小块资源的预定机制。

通过信号量可以在访问临界资源之前,提前知道临界资源的使用情况。

信号量的核心操作:PV原语

sudo find ../../ -name Thread.hpp
cp ../../lesson32/Thread.hpp .

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值