不一定立即崩溃,但属于未定义行为;std::vector所有成员函数均无线程安全保证,读写并发必须加锁,仅写后读可免锁,推荐用std::mutex或c++17的std::shared_mutex保护全部访问。

vector 被多个线程同时写入一定会崩溃吗?
不一定立即崩溃,但属于未定义行为(undefined behavior)。std::vector 的 push_back、resize、clear 等操作可能触发内存重分配,此时若另一个线程正在读或写同一 vector,轻则数据错乱,重则访问已释放内存、double-free 或 segfault。编译器和 STL 实现不保证任何线程安全——哪怕只是两个线程分别调用 push_back 也不行。
只读 + 单写场景下要不要锁?
如果只有一个线程写,其余全只读(且写操作发生在所有读开始前),可以不用锁;但只要存在“读与写并发”,就必须同步。常见误判是认为 operator[] 是 const 就安全——错。它不检查边界,也不阻止写线程修改 size 或 realloc 内存,读线程仍可能访问 dangling pointer。
-
std::vector没有内部锁,所有成员函数都不提供线程安全保证 - 即使只读线程只访问
v[i],若写线程正执行v.push_back(),底层可能已释放旧内存 - 唯一免锁的方案是:写操作完成后再启动所有读线程,且期间无任何写
怎么加锁?推荐 std::mutex + RAII
直接包裹所有对 vector 的访问(包括读和写),用 std::lock_guard 自动管理锁生命周期。不要手写 lock()/unlock(),容易遗漏或异常时未释放。
std::vector<int> data;
std::mutex data_mutex;
// 写
void add_item(int x) {
std::lock_guard<:mutex> lock(data_mutex);
data.push_back(x);
}
// 读
int get_size() {
std::lock_guard<:mutex> lock(data_mutex);
return data.size();
}
// 遍历(注意:不能在锁内做耗时操作)
void process_all() {
std::lock_guard<:mutex> lock(data_mutex);
for (int x : data) {
// 快速处理,避免阻塞其他线程
}
}</:mutex></:mutex></:mutex></int>
- 锁粒度要覆盖所有共享访问点,包括
size()、empty()、at()、data()等 - 避免在锁内调用可能阻塞或抛异常的函数(如 I/O、网络请求)
- 不要把
vector和mutex分开传递,容易漏锁;建议封装成类
有没有更高效的替代方案?
如果写操作极少、读极多,可考虑 std::shared_mutex(C++17),允许多个读线程并发,但写仍独占:
std::vector<int> data;
std::shared_mutex data_mutex;
void add_item(int x) {
std::unique_lock<:shared_mutex> lock(data_mutex);
data.push_back(x);
}
int get_size() {
std::shared_lock<:shared_mutex> lock(data_mutex);
return data.size();
}</:shared_mutex></:shared_mutex></int>
-
std::shared_mutex在 Windows 上性能较差(VS2019 前实现为模拟),Linux(glibc)支持较好 - 若需频繁插入/删除中间元素,
vector本身就不适合并发,应换用std::deque或无锁队列(如moodycamel::ConcurrentQueue) - 真正高并发场景下,单 mutex 会成为瓶颈;此时需分片(sharding)或改用 lock-free 数据结构,但复杂度陡增
锁不是万能解药,关键是识别哪些操作真正共享、是否必须用 vector、以及锁的范围是否最小化。很多崩溃其实源于误以为“只读就不用锁”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











