C++类中修改成员变量的成员函数是否均非线程安全
问题解答
第一个问题:类包含修改成员变量的成员函数,是否所有函数都线程不安全?
结论非常明确:不能这么判定。线程安全的核心判断标准是:多线程并发操作同一对象时,是否会触发数据竞争、是否会破坏对象的合法状态不变量,和函数本身是否修改成员没有绝对的绑定关系。
以下场景中,即使类存在修改成员的函数,部分函数依然是线程安全的:
- 所有修改成员的操作都在对象构造阶段完成,对象发布到多线程访问环境后,没有任何线程会再调用修改接口,此时所有只读成员函数不需要额外同步就是线程安全的。
- 修改操作针对的是原子类型成员,且不存在跨多个变量的一致性约束时,单独的原子读写不需要互斥锁也能保证安全。
第二个问题:Shape::setWH是否非线程安全、需要加std::mutex?
你的判断完全正确。
假设你的mWidth、mHeight是普通int类型的成员变量,无保护并发调用setWH会触发两个层面的问题:
- 标准层面的未定义行为:多线程并发对非原子变量做读写操作,属于C++标准明确定义的数据竞争,程序行为完全不可预期,可能出现写入撕裂、读到随机值等问题。
- 逻辑层面的状态破坏:
setWH的语义是同时更新宽高两个关联值,必须保证两个值的更新是一个不可拆分的原子操作。如果无锁,就可能出现某个线程刚写入新宽度、还没写入新高度时,其他线程读到“新宽度+旧高度”的无效中间状态,破坏Shape对象的合法状态。
注意一个常见误区:不要觉得只有写操作需要加锁。如果类对外提供了读取宽高的getter接口,哪怕getter完全不修改成员,只要存在并发调用setter的可能,getter也必须和setter用同一个互斥锁做同步,否则一样会触发数据竞争、读到无效状态。
对于这个场景的实现,直接在类内声明一个std::mutex成员,在setWH和所有读写宽高的成员函数进入时加锁、退出时解锁(推荐用std::lock_guard自动管理锁生命周期,避免异常场景下死锁)即可,两个int大小的对象用普通互斥锁的性能损耗极低,完全不需要过度优化。
内容的提问来源于stack exchange,提问作者videogamechef
相关产品推荐
相关产品推荐

