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

多生产者-单消费者模型中可以允许多个生产者同时向产品库中放入产品。所以除了保护产品库在多个读写线程下互斥之外,还需要维护生产者放入产品的计数器。

实际需求是地面站需要监控飞机上多个数据源插件的状态以及产生的数据量。地面站和飞机之间要通过链路进行周期性通信,只需要把相关状态按照协议预留字段填充到链路报文中,在地面站解析并显示即可。相关状态要在与地面站通信的进程或者线程中收集起来才能按照协议填充。

这里,每个数据源的状态需要统计ID、当前工作状态、已落盘数据量。多个数据源相当于多个生产者,而汇总这多个状态的相当于消费者。针对此问题,可以使用多生产者-单消费者模式来处理,具体的数据结构可以使用双端口dequeue,多个生产者从队列尾部填充数据,消费者从前端拿数据。

本文的程序是通过设置一起全局结构体用于存储临界区变量的。但是在我们的实际需求中,我们是在A进程里面的多个线程充当生产者,在A进程里面再启动一个线程充当消费者。然后再在消费者线程中创建一个管道或者跨进程消息队列,然后在与地面站交互的进程中读取管道或者队列中的消息,然后进行封装。

#include <iostream>
#include <thread>
#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;       // 仓库所容纳的产品最大个数
    int itemCounter=0;
    std::mutex mtx;         // 互斥量,保护产品缓冲区
    std::mutex itemCounterMtx;
    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);
    itemRepo.repository_notFull.wait(lock, [&itemRepo] {
        bool full = itemRepo.itemQueue.size() >= itemRepo.MaxSize;
        if (full)
        {
            std::lock_guard<std::mutex> lock(stdoutMutex);
            cout << "仓库满了,生产者等待中..." << "thread id = " << std::this_thread::get_id() << endl;
        }
        return !full;
    });

    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);

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

        return !empty;
    });

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

// 生产者任务
void ProducerTask(int th_ID)
{
    bool readyToExit = false;
    while (true)
    {
        //
        this_thread::sleep_for(std::chrono::seconds(1));
        std::unique_lock<std::mutex> lock(gItemRepository.itemCounterMtx);  // 仓库产品消费计数器保持多线程互斥

        if (gItemRepository.itemCounter < kItemsToProduce)
        {
            gItemRepository.itemCounter++;
            ProduceItem(gItemRepository, gItemRepository.itemCounter); // 生产产品
            {
                std::lock_guard<std::mutex> lock(stdoutMutex);
                cout << "Produce Thread " <<th_ID<<"the "<< gItemRepository.itemCounter << " ^th item..." << endl;
            }
        }
        else
        {
            readyToExit = true;
        }

        lock.unlock();
        if (readyToExit)
            break;
    }

    {
        std::lock_guard<std::mutex> lock(stdoutMutex);
        cout << "Producer Thread "<<th_ID<<"exit.... " << endl;
    }
}

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

    }
    {
        std::lock_guard<std::mutex> lock(stdoutMutex);
        cout << "Consumer Thread "<<" exit...." << endl;
    }
}

int main()
{
    std::thread producer1(ProducerTask,1);
    std::thread producer2(ProducerTask,2);
    std::thread producer3(ProducerTask,3);
    std::thread producer4(ProducerTask,4);
    std::thread consumer(ConsumerTask);

    producer1.join();
    producer2.join();
    producer3.join();
    producer4.join();
    consumer.join();

    system("pause");
    return 0;
}
仓库空了,消费者等待中...thread id = 140157878253312
Produce Thread 3the 1 ^th item...
Produce Thread 2the 2 ^th item...
Produce Thread 4the 3 ^th item...
Consume the 1^th item...
Consume the 2^th item...
Consume the 3^th item...
仓库空了,消费者等待中...thread id = 140157878253312
Produce Thread 1the 4 ^th item...
Consume the 4^th item...
仓库空了,消费者等待中...thread id = 140157878253312
Produce Thread 2the 5 ^th item...
Produce Thread 3the 6 ^th item...
Produce Thread 4the 7 ^th item...
Consume the 5^th item...
Consume the 6^th item...
Consume the 7^th item...
仓库空了,消费者等待中...thread id = 140157878253312
Produce Thread 1the 8 ^th item...
Consume the 8^th item...
仓库空了,消费者等待中...thread id = 140157878253312
Produce Thread 3the 9 ^th item...
Produce Thread 2the 10 ^th item...
Produce Thread 4the 11 ^th item...
Consume the 9^th item...
Consume the 10^th item...
Consume the 11^th item...
仓库空了,消费者等待中...thread id = 140157878253312
Produce Thread 1the 12 ^th item...
Consume the 12^th item...
仓库空了,消费者等待中...thread id = 140157878253312
Produce Thread 2the 13 ^th item...
Produce Thread 3the 14 ^th item...
Produce Thread 4the 15 ^th item...
Consume the 13^th item...
Consume the 14^th item...
Consume the 15^th item...
仓库空了,消费者等待中...thread id = 140157878253312
Produce Thread 1the 16 ^th item...
Consume the 16^th item...
仓库空了,消费者等待中...thread id = 140157878253312
Produce Thread 3the 17 ^th item...
Produce Thread 2the 18 ^th item...
Produce Thread 4the 19 ^th item...
Consume the 17^th item...
Consume the 18^th item...
Consume the 19^th item...
仓库空了,消费者等待中...thread id = 140157878253312
Produce Thread 1the 20 ^th item...
Consume the 20^th item...
Consumer Thread  exit....
Producer Thread 2exit.... 
Producer Thread 3exit.... 
Producer Thread 4exit.... 
Producer Thread 1exit.... 



参考链接:https://blog.csdn.net/zy13270867781/article/details/79231775

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然,这里是一个的用C++编写的消费者生产者模式的例子: ```cpp #include <iostream> #include <queue> #include <thread> #include <mutex> #include <condition_variable> std::queue<int> buffer; const int bufferSize = 10; std::mutex mtx; std::condition_variable bufferNotEmpty, bufferNotFull; void producer() { for (int i = 1; i <= 20; ++i) { std::unique_lock<std::mutex> lock(mtx); bufferNotFull.wait(lock, [] { return buffer.size() < bufferSize; }); buffer.push(i); std::cout << "Producer produced item: " << i << std::endl; lock.unlock(); bufferNotEmpty.notify_one(); } } void consumer() { for (int i = 1; i <= 20; ++i) { std::unique_lock<std::mutex> lock(mtx); bufferNotEmpty.wait(lock, [] { return !buffer.empty(); }); int item = buffer.front(); buffer.pop(); std::cout << "Consumer consumed item: " << item << std::endl; lock.unlock(); bufferNotFull.notify_one(); } } int main() { std::thread producerThread(producer); std::thread consumerThread(consumer); producerThread.join(); consumerThread.join(); return 0; } ``` 在这个例子中,我们使用`std::queue`作为缓冲区,`std::mutex`来保护共享资源的访问,`std::condition_variable`用于线程间的同步通信。 生产者函数`producer()`负责将数字1到20依次放入缓冲区中,每次放入一个数字后,会通知消费者线程。 消费者函数`consumer()`负责从缓冲区中取出数字并消费,每次消费一个数字后,会通知生产者线程。 在`main()`函数中,我们创建了一个生产者线程和一个消费者线程,并等待它们的执行完毕。 请注意,这只是一个的示例,实际使用中可能需要更复杂的逻辑来处理并发和同步。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值