移动printf至count变量增减操作前后引发的线程异常行为排查
线程同步问题解析:为何printf位置会影响程序运行
核心问题:未正确保护共享变量count
你的代码存在严重的竞态条件:作为线程同步标志的count,其修改操作(count++/count--)完全脱离了互斥锁的保护。具体来看:
- 在
func1和func2中,你先调用lk1.unlock()释放互斥锁,之后才修改count - 这意味着另一个线程可能在你修改
count的同时,已经获取到互斥锁并读取count的旧值,直接导致count的状态逻辑混乱
为什么printf会"掩盖"问题?
printf是相对耗时的IO操作,当保留count++/count--后的printf时:
- 当前线程解锁后会花时间执行printf,这段缓冲时间足够另一个线程完成唤醒、获取锁、检查条件的完整流程
- 相当于人为给线程调度留出了同步窗口,暂时避免了竞态导致的死锁或循环卡住
而当你注释掉printf或者把它移到count++/count--上方时:
- 线程解锁后会立刻修改
count,此时另一个线程可能还未进入wait状态,或者已获取锁并读取了旧的count值 - 最终导致某个线程的触发条件(
count == 0或count == 1)永远无法满足,程序卡在第49次迭代(i=48)
修复方案:将count的修改纳入锁保护范围
正确的做法是确保count的所有读写操作都在互斥锁的保护下,同时使用wait的谓词版本避免虚假唤醒。修改后的代码示例:
#include <iostream> #include <thread> #include <mutex> #include <chrono> #include<condition_variable> using namespace std; int count = 0; mutex lock1; condition_variable c1; int resource; void func1() { for(int i = 0; i < 50; i++) { unique_lock <mutex> lk1(lock1); // 谓词版本wait:避免虚假唤醒,确保条件满足才继续执行 c1.wait(lk1, []{ return count == 0; }); printf("\nthread 1 is working on resource: %d and i: %d", resource, i); resource++; printf("\nthread 1 work completed, new value: %d and i: %d", resource, i); count++; c1.notify_one(); // unique_lock会在作用域结束时自动释放锁,无需手动调用unlock } } void func2() { for(int i = 0; i < 50; i++) { unique_lock <mutex> lk1(lock1); c1.wait(lk1, []{ return count == 1; }); printf("\nthread 2 is working on resource: %d and i: %d", resource, i); resource--; printf("\nthread 2 work completed, new value: %d and i: %d", resource, i); count--; c1.notify_one(); } } int main() { auto start = chrono::high_resolution_clock::now(); thread worker1(func1); thread worker2(func2); cout<<"\nthread started"<<endl; worker1.join(); worker2.join(); cout<<"\nthread completed"<<endl; auto end = chrono::high_resolution_clock::now(); auto duration = chrono::duration_cast<chrono::milliseconds>(end - start); cout<<duration.count(); }
修复要点:
- 使用
wait的谓词版本:即使收到唤醒信号,也会再次检查条件是否满足,彻底避免虚假唤醒 count的修改在锁保护内:确保count的读写操作完全被互斥锁覆盖,消除竞态条件- 依赖
unique_lock自动解锁:避免手动调用unlock导致的时序错误,简化代码逻辑
内容的提问来源于stack exchange,提问作者ririririri
相关产品推荐
相关产品推荐

