一,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;
}