多线程下遍历vector时遇引用修改是否需添加互斥锁?
必须添加互斥锁,否则存在未定义行为
你的直觉有误,当前的多线程操作必然存在未定义行为,必须通过互斥锁同步,原因如下:
- vector的赋值操作(
allow_list = allow_list_updated)不是原子操作:这个过程会依次执行「销毁原vector的元素→释放原内存→分配新内存→拷贝/移动新元素」等多个步骤,整个过程会被线程调度器打断。 - 读取线程的
std::find遍历依赖vector的迭代器:如果在遍历过程中,更新线程刚好执行了赋值操作的前半段(比如销毁了原元素但还没完成新元素的拷贝),此时读取线程持有的begin()/end()迭代器会变成悬空迭代器,后续的遍历操作会访问已经释放的内存,轻则读取到垃圾数据,重则直接触发程序崩溃。
正确的实现方式
读取线程代码(加锁)
std::mutex mtx; // ... { std::lock_guard<std::mutex> lock(mtx); if (std::find(allow_list->begin(), allow_list->end(), target_string) != allow_list->end()){ allow = true; } }
更新线程代码(加锁)
std::mutex mtx; // ... { std::lock_guard<std::mutex> lock(mtx); // Some operation to a vector called allow_list_updated allow_list = allow_list_updated; }
如果读取操作远多于更新操作,也可以用std::shared_mutex优化并发效率:读取时用std::shared_lock,多个读取线程可以同时获取共享锁;更新时用std::unique_lock,独占锁会阻塞所有其他线程,保证更新的原子性。
内容的提问来源于stack exchange,提问作者Baiqing
相关产品推荐
相关产品推荐

