我有一个使用std :: shared_ptr的双重免费bug并试图了解原因。我在多线程环境中使用shared_ptr,一个线程有时会替换全局数组中的某个元素
std::shared_ptr<Bucket> globalTable[100]; // global elements storage
使用:
globalTable[idx].reset(newBucket);
,另一个线程有时使用:
读取此表std::shared_ptr<Bucket> bkt(globalTable[pIdx]);
// do calculations with bkt-> items
在此之后我收到双重自由错误,而AddressSanitizer说第二个代码试图释放被第一个被破坏的对象。怎么可能?据我所知,shared_ptr必须是完全线程安全的。
答案 0 :(得分:2)
并非std::shared_ptr
上的所有操作都是线程安全的。
具体来说,引用计数是以原子方式管理的,但 负责确保您访问的std::shared_ptr
实例不会同时修改。
您没有履行该责任,导致数据争用和预期的未定义行为,在您的案例中显示为双重免费。
答案 1 :(得分:2)
重置并不能保证您保持线索状态。
分配和引用计数是线程安全的,如此处所述
为了满足线程安全要求,参考计数器是 通常使用等效的std :: atomic :: fetch_add递增 与std :: memory_order_relaxed(递减需要更强 命令安全销毁控制块。)
如果多个线程访问同一个shared_ptr,您可能会遇到竞争条件。
如果多个执行线程没有访问相同的shared_ptr 同步和任何这些访问使用非const成员 shared_ptr的功能然后会发生数据竞争; shared_ptr 原子函数的重载可用于防止数据竞争。
您的功能重置是非常数,因此属于该类别。您需要使用互斥锁或其他同步机制。