std::vector::push_back() 在多线程下无保护调用会导致数据竞争和崩溃;必须用 mutex 串行化写入,或采用 thread_local 缓冲+合并策略;无锁方案不安全,应依实际读写需求选择合适并发模型。

std::vector.push_back() 在多线程下直接调用会崩溃
不能直接从多个线程无保护地调用 push_back()。std::vector 不是线程安全的容器,其内部 size、capacity 和内存重分配(如触发 realloc)都可能被多个线程同时修改,导致数据竞争 —— 表现为段错误、内存损坏、std::length_error 或静默错误。
最简单可靠的方案:用 std::mutex 串行化写入
如果你只是偶尔往 vector 里加点数据,且吞吐量不高,加锁是最清晰、最不容易出错的选择:
std::vector<int> data;
std::mutex data_mutex;
void thread_worker(int value) {
std::lock_guard<std::mutex> lock(data_mutex);
data.push_back(value); // 此时 push_back 是安全的
}
- 所有写线程必须统一使用同一把
data_mutex,读线程如果同时进行,也需加锁(或改用shared_mutex) - 避免在锁内做耗时操作(比如 I/O、复杂计算),否则会严重拖慢并发性能
- 不要把
std::vector的引用或迭代器长期持有并跨锁使用 —— 锁外访问可能因其他线程扩容而失效
高并发场景下避免锁瓶颈:用线程局部缓冲 + 合并
当写入非常频繁(比如每毫秒数千次),单 mutex 成为瓶颈。此时可让每个线程先写自己的 std::vector<T>,最后再合并到全局容器:
thread_local std::vector<int> local_buffer;
void thread_worker(int value) {
local_buffer.push_back(value);
}
// 所有线程 join 后:
for (auto& buf : all_local_buffers) { // 需你自己收集各线程的 buffer(例如通过 vector<vector<int>>)
global_vector.insert(global_vector.end(), buf.begin(), buf.end());
}
-
thread_local确保每个线程独享一份local_buffer,完全无竞争 - 合并阶段仍是单线程,但只发生一次,开销可控;注意
insert()可能触发扩容,建议提前reserve() - 不适用于需要实时可见写入结果的场景(比如一个线程写,另一个线程立刻要读)
别碰 std::vector 的“无锁”幻想
有人试图用 std::atomic<size_t> 手动管理索引、配合 data.data() 直接写内存,或者用 std::vector::data() 加自旋 —— 这些都不安全:
立即学习“C++免费学习笔记(深入)”;
-
std::vector的内存布局和扩容策略是实现定义的,不能假设连续写入不会触发 realloc - 即使你
reserve()足够空间,size()更新仍不是原子的,其他线程无法安全判断当前有效长度 - 没有标准库容器提供无锁写入接口;真需要高性能并发写入,请换用专用结构,比如
boost::lockfree::queue或moodycamel::ConcurrentQueue
真正难的从来不是“怎么加数据”,而是明确写入模式:是否允许延迟合并?是否需要实时读可见?有没有固定容量?没理清这些,光套个 mutex 或换种容器都只是掩盖问题。


















