Linux:通过线程互斥同步实现基于BlockingQueue的生产消费者模型

一、总体调度:主函数Main.cc

cpp 复制代码
#include "BlockQueue.hpp"
#include "Thread.hpp"
#include <string>
#include <vector>
#include <functional>
#include <unistd.h>
#include <ctime>

using namespace ThreadModule;
int a=10;
using Task = std::function<void()>;
using blockqueue_t=BlockQueue<Task>;

void PrintHello()
{
    std::cout<<"hello world"<<std::endl;
}
void Consumer(blockqueue_t &bq)
{
    while(true)
    {
        //1.从blockqueue取下来任务
        Task t;
        bq.Pop(&t);//pop完成后t中会保存任务
        //2.处理这个任务
        t();//消费者私有
    }
}
void Productor(blockqueue_t &bq)
{
    srand(time(nullptr)^pthread_self());
    int cnt=10;
    while(true)
    {
        sleep(1);
        Task t=PrintHello;
        bq.Enqueue(t);
    }
}
//productor和consumer共用此函数
void StartComm(std::vector<Thread<blockqueue_t>> *threads,int num,blockqueue_t &bq,func_t<blockqueue_t> func)
{
    for(int i=0;i<num;i++)
    {
        std::string name="thread-"+std::to_string(i+1);
        threads->emplace_back(func,bq,name);
        threads->back().Start();
    }
}

//启动consumer
void StartConsumer(std::vector<Thread<blockqueue_t>> *thread,int num,blockqueue_t &bq)
{
    StartComm(thread,num,bq,Consumer);
}

//启动productor
void StartProductor(std::vector<Thread<blockqueue_t>> *thread,int num,blockqueue_t& bq)
{
    StartComm(thread,num,bq,Productor);
}
void WaitAllThread(std::vector<Thread<blockqueue_t>> &threads)
{
    for (auto &thread : threads)
    {
        thread.Join();
    }
}
int main()
{
    blockqueue_t *bq=new blockqueue_t(5);
    std::vector<Thread<blockqueue_t>> threads;

    StartConsumer(&threads,3,*bq);
    StartProductor(&threads,1,*bq);
    WaitAllThread(threads);

    return 0;
}

二、线程功能的封装:Thread.hpp

cpp 复制代码
#ifndef __THREAD_HPP__
#define __THREAD_HPP__

#include <iostream>
#include <string>
#include <unistd.h>
#include <functional>
#include <pthread.h>

namespace ThreadModule
{
    template<typename T>
    using func_t=std::function<void(T&)>;

    template<typename T>
    class Thread
    {
    public:
    void Excute()
    {
        _func(_data);
    }
    public:
    Thread(func_t<T> func,T&data,const std::string& name="none-name")
    :_func(func),_data(data),_threadname(name),_stop(true)
    {}
    static void* threadroutine(void* args)//static成员函数没有this
    {
        Thread<T> *self = static_cast<Thread<T> *>(args);
        self->Excute();
        return nullptr;
    }
    bool Start()
    {
        int n=pthread_create(&_tid,nullptr,threadroutine,this);//把this传给threadroutine让其完成调用
        if(!n)
        {
            _stop=false;
            return true;
        }
        else
        {
            return false;
        }
    }
    void Detach()
    {
        if(!_stop)
        {
            pthread_detach(_tid);
        }
    }
    void Join()
    {
        if(!_stop)
        {
            pthread_join(_tid,nullptr);
        }
    }
    std::string name()
    {
        return _threadname;
    }
    void Stop()
    {
        _stop = true;
    }
    ~Thread()
    {}
    private:
    pthread_t _tid;
    std::string _threadname;
    T& _data;//要传入所执行函数的参数
    func_t<T> _func;//线程要执行的函数
    bool _stop;
    };
}
#endif

三、临界区阻塞队列:BlockQueue

cpp 复制代码
#ifndef __BLOCK_QUEUE_HPP__
#define __BLOCK_QUEUE_HPP__

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

template <typename T>
class BlockQueue
{
private:
    bool IsFull()
    {
        return _block_queue.size()==_cap;
    }
    bool IsEmpty()
    {
        return _block_queue.empty();
    }
public:
BlockQueue(int cap):_cap(cap)
{
    _productor_wait_num=0;
    _consumer_wait_num=0;
    pthread_mutex_init(&_mutex,nullptr);
    pthread_cond_init(&_product_cond,nullptr);
    pthread_cond_init(&_consum_cond,nullptr);
}
void Enqueue(T& in)
{
    pthread_mutex_lock(&_mutex);
    while(IsFull())//保证代码的健壮性
    {
         // 生产线程去等待,是在临界区中休眠的!你现在还持有锁呢!!!
        // 1. pthread_cond_wait调用是: a. 让调用线程等待 b. 自动释放曾经持有的_mutex锁 c. 当条件满足,线程唤醒,pthread_cond_wait要求线性
        // 必须重新竞争_mutex锁,竞争成功,方可返回!!!
        // 之前:安全
        _productor_wait_num++;
        pthread_cond_wait(&_product_cond,&_mutex);//  只要等待,必定会有唤醒,唤醒的时候,就要继续从这个位置向下运行!!
        _productor_wait_num--;
    }
    //进行生产
    _block_queue.push(in);
    if(_consumer_wait_num > 0)
            pthread_cond_signal(&_consum_cond); // pthread_cond_broadcast
        pthread_mutex_unlock(&_mutex);
}
void Pop(T *out)
{
    pthread_mutex_lock(&_mutex);
    while(IsEmpty())
    {
    // 消费线程去等待,是在临界区中休眠的!你现在还持有锁呢!!!
    // 1. pthread_cond_wait调用是: a. 让调用进程等待 b. 自动释放曾经持有的_mutex锁
        _consumer_wait_num++;
        pthread_cond_wait(&_consum_cond, &_mutex);  // 伪唤醒
        _consumer_wait_num--;
    }
    //进行消费
    *out=_block_queue.front();//让main.cc的消费者拿到任务
    _block_queue.pop();
    //通知生产者生产
    if(_productor_wait_num>0)
        pthread_cond_signal(&_product_cond);
    pthread_mutex_unlock(&_mutex);
}
~BlockQueue()
{
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_product_cond);
    pthread_cond_destroy(&_consum_cond);

}
private:
    std::queue<T> _block_queue;//阻塞队列,是被整体使用的
    int _cap;//总上限
    pthread_mutex_t _mutex;//保护_block_queue的锁
    pthread_cond_t _product_cond;//专门给生产者提供的条件变量
    pthread_cond_t _consum_cond;//专门给生产者提供的条件变量

    int _productor_wait_num;
    int _consumer_wait_num;

};
#endif

四、Makefile

cpp 复制代码
cp:Main.cc
	g++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:
	rm -f cp
相关推荐
韩楚风5 分钟前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
陈苏同学8 分钟前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
Ambition_LAO14 分钟前
解决:进入 WSL(Windows Subsystem for Linux)以及将 PyCharm 2024 连接到 WSL
linux·pycharm
Pythonliu730 分钟前
茴香豆 + Qwen-7B-Chat-Int8
linux·运维·服务器
你疯了抱抱我31 分钟前
【RockyLinux 9.4】安装 NVIDIA 驱动,改变分辨率,避坑版本。(CentOS 系列也能用)
linux·运维·centos
追风赶月、32 分钟前
【Linux】进程地址空间(初步了解)
linux
栎栎学编程33 分钟前
Linux中环境变量
linux
我是哈哈hh1 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
郭二哈1 小时前
C++——模板进阶、继承
java·服务器·c++
挥剑决浮云 -1 小时前
Linux 之 安装软件、GCC编译器、Linux 操作系统基础
linux·服务器·c语言·c++·经验分享·笔记