c++11 单生产者单消费者模式

注意:

  1. 向标准缓冲区输出字符串时,由于是多线程的,所以需要使用读写锁来同步
  2. 使用了一个deque的队列作为仓库缓冲区,尾部存放头部取出
  3. 当单单模式变成多多模式时,只是针对单变多的某一方多添加一个读写锁
  4. 需要用到C++11中的 互斥锁、条件变量确保多线程间的数据同步

1、单生产者单消费者模式:

  • 顾名思义,单生产者-单消费者模型中只有一个生产者和一个消费者:
  • 生产者不停地往产品库中放入产品;
  • 消费者则从产品库中取走产品;
  • 产品库容积有限制,只能容纳一定数目的产品;
  • 如果生产者生产产品的速度过快,则需要等待消费者取走产品之后,产品库不为空才能继续往产品库中放置新的产品;
  • 相反,如果消费者取走产品的速度过快,则可能面临产品库中没有产品可使用的情况,此时需要等待生产者放入一个产品后,消费者才能继续工作。
#include <thread>
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <deque>
using namespace std;

static const int kItemsToProduce = 20;//定义生产者能够生产的最大产品个数
std::mutex stdoutMutex;//多线程标准输出 同步锁

struct ItemRepository
{
    deque<int> itemQueue;   // 这里用队列代表仓库缓冲区
    int MaxSize = 10;       // 仓库所容纳的产品最大个数
    std::mutex mtx;         // 互斥量,保护产品缓冲区
    std::condition_variable repository_notFull;     // 条件变量, 指产品仓库缓冲区不为满
    std::condition_variable repository_notEmpty;    // 条件变量, 指产品仓库缓冲区不为空
}gItemRepository;   // 产品库全局变量,生产者和消费者操作该变量.

typedef struct ItemRepository ItemRepository;


// 生产 产品
void ProduceItem(ItemRepository &itemRepo, int item)
{
    std::unique_lock<std::mutex> lock(itemRepo.mtx);
    while (itemRepo.itemQueue.size()>=itemRepo.MaxSize) // 判断当前仓库满了
    {
        {
            std::lock_guard<std::mutex> lock(stdoutMutex);
            cout << "仓库满了,生产者等待中..." <<"thread id = "<< std::this_thread::get_id() << endl;
        }
        itemRepo.repository_notFull.wait(lock); // 等待信号量释放锁 生产者等待"仓库缓冲区不为满"这一条件发生(将会跳出循环).
    }
    itemRepo.itemQueue.push_back(item);         // 仓库放入产品
    itemRepo.repository_notEmpty.notify_all();  // 通知消费者仓库不为空
    lock.unlock();  // 释放锁
}

// 消费 产品
int ConsumeItem(ItemRepository &itemRepo)
{
    int data;
    std::unique_lock<std::mutex> lock(itemRepo.mtx);
    while (itemRepo.itemQueue.empty())  // 判断当前仓库空了,等待
    {
        {
            std::lock_guard<std::mutex> lock(stdoutMutex);
            cout << "仓库空了,消费者等待中..." << "thread id = " << std::this_thread::get_id() << endl;
        }
        itemRepo.repository_notEmpty.wait(lock);// 消费者等待"仓库缓冲区不为空"这一条件发生.(等待信号跳出循环)
    }

    data = itemRepo.itemQueue.front();
    itemRepo.itemQueue.pop_front();
    itemRepo.repository_notFull.notify_all();
    lock.unlock();
    return data;
}

// 生产者任务
void ProducerTask()
{
    for (int i = 1;i <= kItemsToProduce;++i)
    {   
        ProduceItem(gItemRepository, i);    // 生产产品
        {
            std::lock_guard<std::mutex> lock(stdoutMutex);
            cout << "Produce the " << i << " ^th item..." << endl;
        }
    }
}

// 消费者任务
void ConsumerTask()
{
    static int cnt = 0;
    while (true)
    {
        //this_thread::sleep_for(std::chrono::seconds(1));
        int item = ConsumeItem(gItemRepository);    // 消费产品
        {
            std::lock_guard<std::mutex> lock(stdoutMutex);
            cout << "Consume the " << item << "^th item..." << endl;
        }
        if (++cnt == kItemsToProduce) break;    // 当消费产品数量 == 生产的数量 退出
    }
}

int main()
{

    std::thread producer(ProducerTask);
    std::thread consumer(ConsumerTask);

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

    system("pause");
    return 0;
}

Produce the 1 ^th item...
Produce the 2 ^th item...
Produce the 3 ^th item...
Produce the 4 ^th item...
Produce the 5 ^th item...
Produce the 6 ^th item...
Produce the 7 ^th item...
Produce the 8 ^th item...
Produce the 9 ^th item...
Produce the 10 ^th item...
仓库满了,生产者等待中...
Consume the 1^th item...
Produce the 11 ^th item...
仓库满了,生产者等待中...
Consume the 2^th item...
Produce the 12 ^th item...
仓库满了,生产者等待中...
Consume the 3^th item...
Produce the 13 ^th item...
仓库满了,生产者等待中...
Consume the 4^th item...
Produce the 14 ^th item...
仓库满了,生产者等待中...
Consume the 5^th item...
Produce the 15 ^th item...
仓库满了,生产者等待中...
Consume the 6^th item...
Produce the 16 ^th item...
仓库满了,生产者等待中...
Consume the 7^th item...
Produce the 17 ^th item...
仓库满了,生产者等待中...
Consume the 8^th item...
Produce the 18 ^th item...
仓库满了,生产者等待中...
Consume the 9^th item...
Produce the 19 ^th item...
仓库满了,生产者等待中...
Consume the 10^th item...
Produce the 20 ^th item...
Consume the 11^th item...
Consume the 12^th item...
Consume the 13^th item...
Consume the 14^th item...
Consume the 15^th item...
Consume the 16^th item...
Consume the 17^th item...
Consume the 18^th item...
Consume the 19^th item...
Consume the 20^th item...
可以用 lambda 进行替换

    // 等待信号不为空的通知,wait 第二参数为true时 向下执行,否则一直等待
    itemRepo.repository_notEmpty.wait(lock, [&itemRepo] {
        bool empty = itemRepo.itemQueue.empty();
        if(empty)
            cout << "仓库空了,消费者等待中..." << "thread id = " << std::this_thread::get_id() << endl;
        return !empty;
    });


    itemRepo.repository_notFull.wait(lock, [&itemRepo] {
        bool full = itemRepo.itemQueue.size() >= itemRepo.MaxSize;
        if(full)
            cout << "仓库满了,生产者等待中..." << "thread id = " << std::this_thread::get_id() << endl;
        return !full;
    });
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章