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;
}
相关推荐
程序猿追19 分钟前
kotlin-retry 接入鸿蒙后,怎样确认它真的会停止重试
开发语言·kotlin·harmonyos
我是人✓20 分钟前
Java文件上传三方式对比:从传统到SpringBoot
java·开发语言
智能直播23 分钟前
网络RTMP拉流不卡顿、声音不同步,一文讲透缓冲区、时间戳
开发语言·ffmpeg·php·音视频·视频编解码
墨云安全1 小时前
内网资产无法暴露到公网,怎么做安全检测?2026 年内网渗透测试的落地路径
开发语言·安全·网络安全·渗透测试·php
摇滚侠1 小时前
《计算机是如何工作的:人人都能懂的计算机软硬件工作原理》第 9 章 机器码与汇编语言 阅读笔记 9
java·开发语言·笔记
Cc.Y2 小时前
Java零基础入门:深入Java核心:文件IO与序列化全解
java·开发语言·python
xier_ran2 小时前
【infra之路】AI 编译器学习笔记(六):重拾 C++——lambda 与 MLIR 中的回调
c++·笔记·学习
jimy13 小时前
c++的 Type Traits (一)
开发语言·c++
别动我齐刘海4 小时前
Linux 系统调试学习2
linux·运维·c++·人工智能·学习·机器学习·机器人
Web极客码4 小时前
Python Ollama 本地 Agent 入门与订单查询实践
开发语言·jvm·python