多线程读写共享数据时shared_ptr指向数据的安全性问询
问题解答
结论:读取得到的shared_ptr<Data>指向的对象有可能被损坏,核心取决于Data类的update方法以及你对该对象的后续访问是否是线程安全的。
为什么Buffer类自身的读写是安全的?
Buffer里的write和read方法都通过同一个std::mutex做了互斥同步:
- 当
read方法持有锁时,write方法会阻塞等待锁释放,反之亦然。 - 这保证了
read从database中拷贝shared_ptr<Data>的操作是原子性的,不会出现database中的元素被半修改的情况,你拿到的shared_ptr必然指向一个完整、有效的Data对象,也不会出现对象在拷贝过程中被销毁的问题(因为锁保护了database的修改,且shared_ptr的引用计数操作本身是原子的)。
风险点在哪里?
当read返回shared_ptr<Data>之后,这个对象的生命周期由shared_ptr的引用计数维护,但Buffer的mutex不再对该Data对象的访问做同步:
- 后续
write线程可以再次获取锁,找到同一个id对应的shared_ptr<Data>,然后调用data->update()。 - 如果你的
Data类的update方法没有内部同步机制(比如没有加锁、没有使用原子类型存储数据),同时读取线程在拿到shared_ptr后也在访问该Data对象的成员变量,那么这两个线程的操作就会形成竞态条件,直接导致Data对象的数据损坏。
怎么避免损坏?
- 给
Data类的所有修改和访问方法加上同步保护(比如内部加std::mutex); - 把
Data类的成员变量换成原子类型(如果适合用原子操作实现逻辑); - 或者在
read之后,不再允许write修改该Data对象(比如用不可变对象模式,修改时创建新的Data实例替换旧的)。
内容的提问来源于stack exchange,提问作者crazymumu
相关产品推荐
相关产品推荐

