C++多线程中通过指针调用其他类方法的线程安全问题
多线程加锁逻辑问题解答
首先明确结论:仅给共享变量的写操作加锁、不对并发读操作做线程安全保护的逻辑是不可靠的,只要存在读写并发就会触发C++标准定义的数据竞争,属于未定义行为。
现有代码的具体问题
- 首先存在低级笔误:类A中声明的成员变量是
occurrence,但operation()、getOccurence()中访问的变量名是occurence(少了一个r),这个问题会直接导致编译失败,需要先统一命名才能验证逻辑。 - 读操作无保护的线程安全风险:按照C++内存模型规则,多线程并发访问同一个非原子变量时,只要存在至少一个写操作,且没有同步机制建立happens-before关系,就构成数据竞争,可能出现读值撕裂、读到过期值、程序随机崩溃等问题。
你当前main函数里的流程比较特殊:所有异步写线程启动后,主线程先通过fut.wait()等所有任务执行完成才调用getOccurence()读值,std::future::wait()本身会和异步线程的结束点建立同步关系,保证主线程能看到所有线程对变量的修改,这个特定场景下的读是安全的。但只要你后续在写操作执行的同时,有任何线程并发调用getOccurence(),就会立刻触发未定义行为,不能依赖这种特殊时序的巧合。 - 其他只读成员的安全边界:你提到
operation()中除了occurrence之外的类成员仅做读取、不修改,如果这些成员是在所有子线程启动前就完成初始化,启动后没有任何线程对其做写操作,那么多线程并发读是安全的,不需要额外加锁;只要这些成员在线程运行期间存在任何写操作,并发读同样需要同步保护。
正确修正方式
- 方案1:所有对
occurrence的访问(无论读写)都放在同一个互斥锁的保护范围内,修改getOccurence()实现:
int getOccurrence() // 注意修正函数名拼写和变量名统一 { lock_guard<mutex> my_lock(m); return occurrence; }
- 方案2:如果仅需要保护
occurrence这一个简单整型变量,可以直接将其声明为std::atomic<int>类型,原子变量本身自带线程安全保证,自增、读取操作不需要额外加mutex,性能也更好。 - 统一修正所有变量、函数名的拼写错误,保证和声明一致。
内容的提问来源于stack exchange,提问作者user2456835
相关产品推荐
相关产品推荐

