C++多线程共享资源问题:std::logic_error与段错误排查
C++多线程共享资源与互斥锁问题排查
常见错误根源
你遇到的段错误和std::logic_error,本质都是共享资源(cameras向量)的访问未被完全保护导致的竞态条件:
- 段错误:多线程同时读写向量时,一个线程修改向量(插入/删除元素)导致另一个线程的迭代器或内存访问失效。
std::logic_error:通常是调用vector::at()时索引越界——比如线程A先读取向量长度,还没访问元素,线程B就删除了元素,导致之前的长度信息失效。
互斥锁正确使用原则
- 所有访问共享资源的路径必须加锁:哪怕是
size()这类只读操作,多线程环境下只读操作也会和写操作发生竞态。 - 用RAII风格管理锁:优先用
std::lock_guard或std::unique_lock,避免手动调用lock()/unlock()导致的锁泄漏(比如异常时忘记解锁)。 - 锁包裹完整的操作逻辑:不要拆分锁,比如“检查向量长度+访问元素”必须放在同一个锁的作用域内,避免中间出现其他线程修改资源的窗口。
代码修正示例
假设你的原始代码存在典型的锁缺失问题,以下是修正后的版本:
错误代码(模拟常见问题)
#include <vector> #include <mutex> #include <thread> #include <iostream> std::vector<int> cameras; std::mutex mtx; void add_camera(int id) { // 错误:修改共享资源未加锁 cameras.push_back(id); } void print_camera_count() { if (1 == 1) { // 错误:读取size未加锁,可能和写操作竞态 std::cout << "Camera count: " << cameras.size() << std::endl; } } void access_camera(int idx) { // 错误:先读size再加锁,中间存在竞态窗口 if (idx < cameras.size()) { std::lock_guard<std::mutex> lock(mtx); // 此时向量长度可能已被修改,idx越界触发logic_error std::cout << "Camera " << idx << ": " << cameras.at(idx) << std::endl; } } int main() { std::thread t1(add_camera, 1); std::thread t2(print_camera_count); std::thread t3(access_camera, 0); t1.join(); t2.join(); t3.join(); return 0; }
修正后的代码
#include <vector> #include <mutex> #include <thread> #include <iostream> std::vector<int> cameras; std::mutex mtx; void add_camera(int id) { std::lock_guard<std::mutex> lock(mtx); // 修改前加锁 cameras.push_back(id); } void print_camera_count() { if (1 == 1) { std::lock_guard<std::mutex> lock(mtx); // 读取size前加锁 std::cout << "Camera count: " << cameras.size() << std::endl; } } void access_camera(int idx) { std::lock_guard<std::mutex> lock(mtx); // 先加锁,再执行完整逻辑 if (idx < cameras.size()) { std::cout << "Camera " << idx << ": " << cameras.at(idx) << std::endl; } else { std::cerr << "Invalid camera index: " << idx << std::endl; } } int main() { std::thread t1(add_camera, 1); std::thread t2(print_camera_count); std::thread t3(access_camera, 0); t1.join(); t2.join(); t3.join(); return 0; }
关键修复说明
- 所有对
cameras的读写操作都被std::lock_guard包裹,确保同一时间只有一个线程能访问向量。 - 将“检查长度+访问元素”的完整逻辑放在锁内,消除竞态窗口。
std::lock_guard会在作用域结束时自动解锁,即使发生异常也不会导致锁泄漏。
内容的提问来源于stack exchange,提问作者Gabi5537
相关产品推荐
相关产品推荐

