在多生产者多消费者的场景下,基于双list的高性能消息对列

背景

之前写了一篇基于单生产者单消费者的无锁队列,链接如下
https://blog.csdn.net/lab1228/article/details/127357286

在多生产者多消费者的场景下,常规操作是对单个队列加锁,但是这样锁竞争会导致性能变差,于是基于双队列,分拆生产者和消费者队列,这样消费者和生产者之间就不会出现锁竞争,提升性能。

代码实现

#include <iostream>
#include <list>
#include <condition_variable>
//1.内部有两个list,生产者把消息放到生产队列,消费者从消费队列取消息
//2.使用了两把锁分别管理两个队列
//3.使用了两个条件变量分别管理生产者和消费者的等待唤醒
//4.队列可以有block / nonblock两种状态
//5.如果为block,则生产者队列最大长度为maxQueueSize,
//6.如果为nonblock,则不限制最大长度
template<class T>
class MsgQueue
{
public:
    MsgQueue(bool isNoBlock = true, uint32_t maxQueueSize = 1024):
        _isNoBlock(isNoBlock), _maxQueueSize(maxQueueSize)     
    {

    }
    ~MsgQueue() {

    }

    //如果为BLOCK模式,队列满的情况下会一直阻塞至队列交换后,才能完成
    int put(const T data)
    {
        std::unique_lock<std::mutex> lock(_mtxPut);
        if (_isNoBlock)
        {
            _listPut->emplace_back(std::move(data));
        }
        else
        {
             //判断是否满,满则阻塞
            while (_maxQueueSize <= _listPut->size())
            {
                _cvPut.wait(lock);
            }
            _listPut->emplace_back(std::move(data));
            _cvGet.notify_one();
        }
        return 0;
    }
    int get(T& data)
    {
        std::unique_lock<std::mutex> lock(_mtxGet);
        if (!_listGet->empty())
        {
            data = _listGet->front();
            _listGet->pop_front();
        }
        else
        {
            if (swap() > 0)
            {
                data = _listGet->front();
                _listGet->pop_front();
            }
            else {

                return -1;
            }

        }
        return 0;
    }
    private:

    int swapList()
    {
      
        return _listGet.size();
    }
    int swap()
    {
        std::unique_lock<std::mutex> lock(_mtxPut);
        if (_isNoBlock)
        {
            std::list<T>* listTmp = _listGet;
            _listGet = _listPut;
            _listPut = listTmp;
            return _listGet->size();
        }

        while (_listPut->empty())
        {
            _cvGet.wait(lock);
        }
        std::list<T>* listTmp = _listGet;
        _listGet = _listPut;
        _listPut = listTmp;
        _cvPut.notify_one();
        return _listGet->size();
        
        
    }
    std::list<T> _list1;
    std::list<T> _list2;
    //指向当前可用于消费的队列
    std::list<T>* _listGet = &_list1;
    //指向当前可用于生产的队列
    std::list<T>* _listPut = &_list2;
    //生产者队列最大长度
    uint32_t _maxQueueSize = 5;
    bool _isNoBlock = true;
    std::mutex _mtxPut;
    std::mutex _mtxGet;
    std::condition_variable _cvPut;
    std::condition_variable _cvGet;
};
    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老黄叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值