C++ 生产者消费者模式的简单实现

01 模式简介

注意,生产者消费者模式并不是23中设计模式之一。

生产者消费者模式可以理解为在生产者和消费者之间添加一个缓冲区,生产者只负责向缓冲区添加元素,而消费者只负责从缓冲区提取元素并使用。

这么做可以对生产者与消费者进行解耦,这样一来消费者不直接调用生产者,使得生产者的不会因为生产者的具体处理而阻塞,充分利用资源。

02 思路介绍

代码中的具体元素为Stone类,生产者线程负责向缓冲类Busket中添加具体元素,而消费者线程则在缓冲类中的队列不为空的时候取用这些元素。

其中缓冲类需要带一把互斥锁,使得不论是被添加还是被取用的动作都能保证是原子性的。

用到了boost库的thread_group,如果不了解可以自行创建线程进行调试。

03 结果截取

NUM IN BUSKET NOW IS : 20
THREAD 0x700008668000 GET A STONE WEIGHT IS 75.

NUM IN BUSKET NOW IS : 19
THREAD 0x7000085e5000 GET A STONE WEIGHT IS 35.

NUM IN BUSKET NOW IS : 18
THREAD 0x700008562000 GET A STONE WEIGHT IS 98.

NUM IN BUSKET NOW IS : 17
THREAD 0x7000086eb000 GET A STONE WEIGHT IS 42.

NUM IN BUSKET NOW IS : 16
THREAD 0x7000084df000 GET A STONE WEIGHT IS 99.

NUM IN BUSKET NOW IS : 15
THREAD 0x7000082d3000 GET A STONE WEIGHT IS 68.

04 Show me the code

#include 
#include 
#include 
#include 
#include 

using namespace std;

// 用于防止多个线程抢占终端输出导致输出混乱的锁
mutex log_mt;

// 具体的元素
class Stone {
public:
    float weight;

    ~Stone() {}

    Stone() {
        weight = rand() % 100;
    }
};


// 缓冲类
class Busket {
private:
    deque<Stone> dq;
public:
    mutex mt;
  
    bool empty() const {
        return dq.empty();
    }

    const Stone get() {
        Stone temp = *(dq.begin());
        dq.erase(dq.begin());
        return temp;
    }

    void add() {
        dq.emplace_back(Stone());
    }

    const unsigned int size() {
        return dq.size();
    }
};


// 生产者类
class Provider {
private:
    int aim_num;
    Busket* pbusket;
  
public:
    ~Provider() {}

    Provider(const int num, Busket& busket)
    : aim_num(num), pbusket(&busket) {}

    void build_stone() {
        const int NUM_TO_BUILD = rand() % 20;
        int ct = 0;

        while (pbusket->size() < aim_num && ct < NUM_TO_BUILD) {
            ++ct;
            lock_guard<mutex> lg(pbusket->mt);
            pbusket->add();
        }
    }
};


// 消费者类
class Custmer {
private:
    Busket* pbusket;
  
public:
    ~Custmer() {
        pbusket = nullptr;
    }

    Custmer(Busket& busket)
    : pbusket(&busket) {}

    const Stone get() const {
        lock_guard<mutex> lg(pbusket->mt);
        cout << "NUM IN BUSKET NOW IS : " << pbusket->size() << endl;
        return pbusket->get();
    }

    bool can_take() const {
        return !pbusket->empty();
    }
};


// 生产者子函数
void func_provider(Provider& provider) {
    while (1) {
        this_thread::sleep_for(chrono::seconds(1));
        provider.build_stone();
    }
}


// 消费者子函数
void func_custmer(Custmer& custmer) {
    while(1) {
        this_thread::sleep_for(chrono::seconds(1));
        lock_guard<mutex> lg(log_mt);
        if (custmer.can_take()) {
            int temp = custmer.get().weight;
            cout << "THREAD " << this_thread::get_id() << " GET A STONE WEIGHT IS " << temp << "." << endl << endl;
        }
    }
}


int main() {
    // 缓冲区
    unique_ptr<Busket> pbusket(new Busket());

    // 生产者
    unique_ptr<Provider> pprovider(new Provider(200, *pbusket));

    // 消费者
    unique_ptr<Custmer> pcustmer(new Custmer(*pbusket));


    // boost线程池
    boost::thread_group threads;

    // 生产者
    threads.create_thread(boost::bind(func_provider, *pprovider));

    // 创建10个消费者
    for (int i = 0; i < 10; ++i) {
        threads.create_thread(boost::bind(func_custmer, *pcustmer));
    }

    // main函数阻塞
    threads.join_all();


    return 0;
}

你可能感兴趣的:(设计模式)