C++线程安全队列对比

一,mutex + cond + std::queue, 100万条string

测试代码:

cpp 复制代码
#include <string>
#include <mutex>
#include <thread>
#include <iostream>
#include <cassert>
#include <chrono>

#include "bthreadsafequeue.h".h"
using namespace mlib;

BThreadSafeQueue<std::string> bfifo;
constexpr uint32_t max_producer =  10000 * 100 ;

int main()
{
    auto start = std::chrono::steady_clock::now();
    std::thread consumer([=]
                         {
                             uint32_t counts = 0;
                             std::string str;
                             while (true)
                             {
                                 if (bfifo.waitPopFor(str, std::chrono::milliseconds(500)))
                                 {
                                     // 哨兵:空字符串代表退出
                                     if (str.empty())
                                     {
                                         std::cout << "consumer receive sentinel, exit loop\n";
                                         break;
                                     }
                                     ++counts;
                                     std::cout << "consumer " << str << std::endl;
                                 }
                                 // 超时什么都不做,继续循环
                             }
                             std::cout << "Dequeue times = " << counts << std::endl;
                         });

    std::thread producer1([=]
                          {
                              for (int i = 0; i < max_producer; ++i)
                              {
                                  bfifo.push(std::to_string(i));

                                      std::cout << "producer1 enqueue" << i << std::endl;
                              }
                          });

    std::thread producer2([=]
                          {
                              for (int i = 0; i < max_producer; ++i)
                              {
                                  bfifo.push(std::to_string(i));

                                      std::cout << "producer2 enqueue" << i << std::endl;
                              }
                          });

    std::thread producer3([=]
                          {
                              for (int i = 0; i < max_producer; ++i)
                              {
                                  bfifo.push(std::to_string(i));

                                      std::cout << "producer3 enqueue" << i << std::endl;
                              }
                          });


    std::thread producer4([=]
                          {
                              for (int i = 0; i < max_producer; ++i)
                              {
                                  bfifo.push(std::to_string(i));

                                      std::cout << "producer4 enqueue" << i << std::endl;
                              }
                          });


    std::thread producer5([=]
                          {
                              for (int i = 0; i < max_producer; ++i)
                              {
                                  bfifo.push(std::to_string(i));

                                      std::cout << "producer5 enqueue" << i << std::endl;
                              }
                          });



    // 等待所有生产者写完数据
    producer1.join();
    producer2.join();
    producer3.join();
    producer4.join();
    producer5.join();

    // ✅关键:生产者全部结束之后,推送哨兵消息给消费者,通知退出
    bfifo.push("");

    consumer.join();

    auto end = std::chrono::steady_clock::now();
    auto cost_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    std::cout << "All thread exited, cost_ms:" << cost_ms.count() << std::endl;

    // 此时队列对象还在,Block内存不会释放(RSS居高不下,issue#449现象)
    std::this_thread::sleep_for(std::chrono::seconds(10));

    return 0;
}

结果:

时间:

Dequeue times = 5000000

All thread exited, cost_ms:134590

内存占用:289M

44278 cmy 20 0 443712 296844 4008 S 4.3 8.7 0:04.34 testQueuePro ()

内存 44278 cmy 20 0 443712 296844 4008 S 4.3 8.7 0:04.34 testQueuePro

plaintext

复制代码
44278 cmy       20   0  443712 296844   4008 S   4.3   8.7   0:04.34 testQueuePro

单位全部 KB

表格

字段 数值 换算 说明
VIRT 虚拟内存 443712 KB ~433 MB 整个进程虚拟地址空间 (可执行文件、所有 so 库、mmap、堆、栈,不等于实际占用内存)
RES 常驻物理内存 296844 KB ~289 MB 真正占用物理 RAM,这是重点
SHR 共享内存 4008 KB ~3.9 MB 共享库内存

私有物理内存(进程自己独占内存) = RES‑SHR = 296844‑4008 = 292836 KB ≈ 286 MB

二:

无锁moodycamel(内存一直在峰值不释放)

52727 cmy 20 0 479164 176772 3972 S 3.0 5.2 0:01.32 testQueuePro

结果:

Dequeue times = 2999998

All thread exited, cost_ms:123776

consumer receive sentinel, exit loop

Dequeue times = 3003028

All thread exited, cost_ms:127152

内存:

51093 cmy 20 0 413628 134892 4036 S 3.0 3.9 0:03.92 testQueuePro

复制代码
#include <string>
#include <mutex>
#include <thread>
#include <iostream>
#include <cassert>
#include <chrono>

#include "blockingconcurrentqueue.h"

struct Traits : public moodycamel::ConcurrentQueueDefaultTraits
{
    static constexpr size_t MAX_SUBQUEUE_SIZE = 5000000;
};

moodycamel::BlockingConcurrentQueue<std::string, Traits> bfifo(10000 * 10 * 10);
constexpr uint32_t max_producer =  10000 * 100 ;
static std::atomic<int> ipush = 0 ;
int main()
{
    auto start = std::chrono::steady_clock::now();
    std::thread consumer([&]
                         {
                             uint32_t counts = 0;
                             std::string str;
                             while (true)
                             {
                                 if (bfifo.wait_dequeue_timed(str, std::chrono::milliseconds(500)))
                                 {

                                     // 哨兵:空字符串代表退出
                                     if (str.empty())
                                     {
                                         std::cout << "Got sentinel, drain remaining items...\n";
                                         // 读到哨兵之后!继续非阻塞捞光队列剩余所有消息!
                                         while (bfifo.try_dequeue(str))
                                         {
                                             ++counts;

                                         }
                                         break;
                                     }
                                     ++counts;
                                     // std::cout << "consumer " << str << std::endl;
                                 }
                                 // 超时什么都不做,继续循环
                             }
                             std::cout << "Dequeue times = " << counts << std::endl;
                         });

    std::thread producer1([&]
                          {
                              for (int i = 0; i < max_producer; ++i)
                              {
                                  ipush++;
                                  if (!bfifo.enqueue(std::to_string(i)))
                                  {
                                      std::cout << "Failed to enqueue" << std::endl;
                                  }
                                  // else
                                  //     std::cout << "producer1 enqueue" << i << std::endl;
                              }
                          });

    std::thread producer2([&]
                          {
                              for (int i = 0; i < max_producer; ++i)
                              {
                                  ipush++;
                                  if (!bfifo.enqueue(std::to_string(i)))
                                  {
                                      std::cout << "Failed to enqueue" << std::endl;
                                  }
                                  // else
                                  //     std::cout << "producer2 enqueue" << i << std::endl;
                              }
                          });

    std::thread producer3([&]
                          {
                              for (int i = 0; i < max_producer; ++i)
                              {
                                  ipush++;
                                  if (!bfifo.enqueue(std::to_string(i)))
                                  {
                                      std::cout << "Failed to enqueue" << std::endl;
                                  }
                                  // else
                                  //     std::cout << "producer3 enqueue" << i << std::endl;
                              }
                          });


    std::thread producer4([&]
                          {
                              for (int i = 0; i < max_producer; ++i)
                              {
            ipush++;
                                  if (!bfifo.enqueue(std::to_string(i)))
                                  {
                                      std::cout << "Failed to enqueue" << std::endl;
                                  }
                                  // else
                                  //     std::cout << "producer4 enqueue" << i << std::endl;
                              }
                          });


    std::thread producer5([&]
                          {
                              for (int i = 0; i < max_producer; ++i)
                              {
            ipush++;
                                  if (!bfifo.enqueue(std::to_string(i)))
                                  {
                                      std::cout << "Failed to enqueue" << std::endl;
                                  }
                                  // else
                                  //     std::cout << "producer5 enqueue" << i << std::endl;
                              }
                          });



    // 等待所有生产者写完数据
    producer1.join();
    producer2.join();
    producer3.join();
    producer4.join();
    producer5.join();


    // ✅关键:生产者全部结束之后,推送哨兵消息给消费者,通知退出
    bfifo.enqueue("");

    consumer.join();

    std::cout << "count:" <<  ipush << std::endl;
    auto end = std::chrono::steady_clock::now();
    auto cost_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    std::cout << "All thread exited, cost_ms:" << cost_ms.count() << std::endl;

    // 此时队列对象还在,Block内存不会释放(RSS居高不下,issue#449现象)
    std::this_thread::sleep_for(std::chrono::seconds(10));

    return 0;
}
相关推荐
Demon--hx1 小时前
C++访问权限问题
开发语言·c++
乐观勇敢坚强的老彭1 小时前
c++信息学竞赛数组大小规划与避坑速查表
开发语言·c++
格林威2 小时前
C#图像夜间识别率提升:使用OpenCvSharp和Halcon融合DeepSORT实现复杂场景下准确识别
开发语言·人工智能·数码相机·机器学习·计算机视觉·c#·视觉检测
深海向晚2 小时前
NX二次开发:递归遍历特征组并收集所有特征
c++
重生之小比特2 小时前
【初阶C++】list
开发语言·c++·list
SunnyDays10112 小时前
如何使用 Python 添加和编辑 Excel VBA 宏(无需安装 Excel)
开发语言·python·excel·vba
郝学胜-神的一滴2 小时前
CMake 047:解锁安装阶段自定义操作,告别配置阶段提前执行坑
运维·服务器·c++·游戏引擎·图形渲染·opengl
zhanghaha13142 小时前
Python进阶教程:24_Markdown 转 HTML 零基础超详细教程
开发语言·python·html
似水এ᭄往昔2 小时前
【QT】--常用控件(QWidget的核心属性)
服务器·开发语言·qt