使用基于C++11的线程池实现生产者-消费者模型(demo)

这篇博客演示了一个多线程应用,包含一个生产者线程不断生产数据并将其放入数据队列,以及一个消费者线程从队列中取出数据进行处理。如果处理失败,数据会被重新加入队列等待重试。线程池用于管理和调度任务,提高了系统效率。同时,代码展示了如何使用互斥锁和条件变量来保证线程安全。
摘要由CSDN通过智能技术生成
模型:
一个输入触发的生产者线程,不断的生产数据,一个消费者背景线程,不断的取出数据,若数据处理失败,需重新加入数据队列等待重新处理。
#include <atomic>
#include <thread>
#include <assert.h>
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <shared_mutex>
#include <atomic>
#include "threadPool.h"

using namespace std;

mutex dataListLock;
set<int> dataList;

int RET_OK = 0;
int RET_ERROR = -1;

//  demo用于随机产生返回结果
bool randomResult()
{
    static int i = 1;
    i++;
    return (i % 5) == 0 || (i % 7) == 0 || (i % 3) == 0;
}

void producerFunc()
{
    static int value = 10;
    value++;
    if (randomResult()) {  //  生产者正在生产数据 
        unique_lock<mutex> uniqueLock(dataListLock);
        cout << "producer processing. dataList.size(): " << dataList.size() << endl;
    } else {  //  生产者成功生产一个数据
        unique_lock<mutex> uniqueLock(dataListLock);
        dataList.insert(value);
        cout << "produce a new. value : " << value << "  dataList.size(): "<< dataList.size() << endl;
    }
}

void producerThread(threadPool *p)
{
    int input = 0;
    while (true) {
        cin >> input;  //  输入触发
        p->addTask(producerFunc);
    }

}

int consumerFunc(int value)
{
    int ret = RET_ERROR;
    if (randomResult()) {  //  处理失败将数据加入队列等待重新处理
        ret =  RET_ERROR;
        unique_lock<mutex> uniqueLock(dataListLock);
        dataList.insert(value);
        cout << "consumer process fail. value : " << value  << "  dataList.size(): "<< dataList.size() << endl;
    } else {
        unique_lock<mutex> uniqueLock(dataListLock);
        cout << "consumer process success. value : " << value << "  dataList.size(): "<< dataList.size() << endl;
        ret =  RET_OK;
    }

    return ret;
}

void consumerThread(threadPool *p)
{
    while (true) {
    	//  可选择休眠
    	//  this_thread::sleep_for(chrono::seconds(5));  
        set<int> dataListTmp;

		//  将生产者产生的数据全部取出等待处理
        {
            unique_lock<mutex> uniqueLock(dataListLock);
            dataList.swap(dataListTmp);
        }
		
		/*可监听处理结果
		map<int, future<int>> retList;
		*/
		//  循环处理产生的数据
        for (auto &value : dataListTmp) {
            retList[value] = p->addTask(consumerFunc, value);
        }
        /*根据处理结果处理
        for (auto &value : retList) {
        	auto ret = value.second.get(); // 阻塞等待结果出来
        }
		*/
    }
}

void initTask()
{
    unique_lock<mutex> uniqueLock(dataListLock);
    dataList.insert(1);
    dataList.insert(2);
    dataList.insert(3);
    dataList.insert(4);
}

int main()
{
    //  初始化任务
    initTask();

    threadPool producerPool(2); // 生产者线程池 2个线程
    threadPool consumerPool(2); // 消费者线程池 2个线程
    thread producer(producerThread, &producerPool);
    thread consumer(consumerThread, &consumerPool);

    producer.join();
    consumer.join();

    return 0;
}

运行结果:
NAVER@CD-1113-1 MINGW64 /c/Code/C++/Test/testMain
$ g++ -g -o main main.cpp

NAVER@CD-1113-1 MINGW64 /c/Code/C++/Test/testMain
$ ./main.exe
consumer process success. value : 1  dataList.size(): 0
consumer process fail. value : 2  dataList.size(): 1
consumer process fail. value : 4  dataList.size(): 2
consumer process success. value : 3  dataList.size(): 2
consumer process fail. value : 2  dataList.size(): 1
consumer process fail. value : 4  dataList.size(): 1
consumer process success. value : 2  dataList.size(): 0
consumer process fail. value : 4  dataList.size(): 1
consumer process fail. value : 4  dataList.size(): 1
consumer process success. value : 4  dataList.size(): 0
1
producer processing. dataList.size(): 0
2
produce a new. value : 12  dataList.size(): 1
consumer process fail. value : 12  dataList.size(): 1   
consumer process fail. value : 12  dataList.size(): 1   
consumer process success. value : 12  dataList.size(): 0
3
produce a new. value : 13  dataList.size(): 1
consumer process fail. value : 13  dataList.size(): 1   
consumer process success. value : 13  dataList.size(): 0
4
producer processing. dataList.size(): 0
3
producer processing. dataList.size(): 0
1
produce a new. value : 16  dataList.size(): 1
consumer process success. value : 16  dataList.size(): 0
2312
producer processing. dataList.size(): 0
123
producer processing. dataList.size(): 0
123
produce a new. value : 19  dataList.size(): 1
consumer process fail. value : 19  dataList.size(): 1
consumer process fail. value : 19  dataList.size(): 1
consumer process success. value : 19  dataList.size(): 0
线程池使用参考:https://www.cnblogs.com/lzpong/p/6397997.html
代码很简单,源码如下:
#pragma once
#ifndef THREAD_POOL_H
#define THREAD_POOL_H

#include <vector>
#include <queue>
#include <thread>
#include <atomic>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>

using namespace std;

//线程池,可以提交变参函数或拉姆达表达式的匿名函数执行,可以获取执行返回值
//不支持类成员函数, 支持类静态成员函数或全局函数,Opteron()函数等
class threadPool
{
    using Task = function<void()>;
    // 线程池
    vector<thread> pool;
    // 任务队列
    queue<Task> tasks;
     // 同步
    mutex m_lock;
     // 条件阻塞
    condition_variable cv;
     // 是否关闭提交
    atomic<bool> stoped;

public:
    inline threadPool(uint8_t inputThreadNum) : stoped(false)
    {
        for (uint8_t i = 0; i < inputThreadNum; ++i) {   //初始化线程数量
            auto workFunc = [this] { // 工作线程函数
                while(!this->stoped) {
                   function<void()> task;
                    {   // 获取一个待执行的 task
                        unique_lock<mutex> lock(this->m_lock);
                        // wait 直到有 task 判断一次如果条件不满足则会一直阻塞知道被notify,如果满足则直接继续执行
                        //  若条件不满足,wait函数会自动unlock,直到被notify后会重新lock
                        this->cv.wait(lock, [this] { return this->stoped.load() || !this->tasks.empty(); });
                        if (this->stoped && this->tasks.empty()) { // 虽然停止了,但还有任务没执行完,依然优先执行任务
                            return;
                        }
                        task = move(this->tasks.front()); // 取一个 task
                        this->tasks.pop();
                    }
                    task();
                }
            };
            pool.emplace_back(workFunc);
        }
    }

    inline ~threadPool()
    {
        stoped.store(true);
        cv.notify_all(); // 唤醒所有线程执行
        for (thread& thread : pool) {
            if(thread.joinable()) {
                thread.join(); // 等待任务结束, 前提:线程一定会执行完
            }
        }
    }

public:
    // 提交一个任务
    // 调用.get()获取返回值会等待任务执行完,获取返回值
    // 有两种方法可以实现调用类成员,
    // 一种是使用   bind: .addTask(bind(&Dog::sayHello, &dog));
    // 一种是用 mem_fn: .addTask(mem_fn(&Dog::sayHello), &dog)
    template<class F, class... Args>
    //  decltype自动推导出类型
    auto addTask(F&& f, Args&&... args) -> future<decltype(f(args...))>
    {
        if (stoped.load()) {
            throw runtime_error("addTask on ThreadPool is stopped.");
        }

        using RetType = decltype(f(args...)); // typenameresult_of<F(Args...)>::type, 函数 f 的返回值类型
        auto task = make_shared<packaged_task<RetType()> >( bind(forward<F>(f),forward<Args>(args)...) );
        auto future = task->get_future();

        {    // 添加任务到队列
            unique_lock<mutex> lock(this->m_lock);
            tasks.emplace([task](){ (*task)();});
        }

        cv.notify_one(); // 唤醒一个线程执行 若没有空闲线程,则说明tasks一直不为空,没有线程被阻塞,不需要被唤醒

        return future;
    }
};

#endif
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值