含for循环的双线程条件变量未触发问题求助
问题分析与解决方案
嘿,我来帮你拆解下这个问题!你的核心问题出在互斥锁的作用范围上,咱们一步步理清楚:
为什么for循环里条件变量通知无效?
你在simulate_event_readin函数开头就声明了std::lock_guard<std::mutex> lck(mtx),这意味着从函数开始到结束,整个for循环的全程,互斥锁都被线程一牢牢攥在手里。而线程二的condVar.wait()必须先拿到互斥锁,才能检查event_angekommen的状态——但锁一直被线程一占着,线程二根本抢不到锁,自然就永远卡在等待状态,连条件都没法检查,更别说响应通知了。
至于去掉for循环后能工作,是因为线程一执行完函数就释放了锁,线程二能顺利获取锁并检查到event_angekommen为true,所以能触发一次处理逻辑。
修正方案
我们需要调整锁的作用范围,只在修改共享数据(csv_reihe和event_angekommen)的时候加锁,其他时间(比如sleep的时候)释放锁,让线程二能正常工作。另外还要给线程二加个退出逻辑,避免CSV处理完后线程二无限等待。
修正后的线程一代码
std::mutex mtx; std::condition_variable condVar; bool event_angekommen{false}; bool stop_processing{false}; // 新增结束标志,用来通知线程二退出 void simulate_event_readin(CSVLeser leser, int sekunden, std::vector<std::string> &csv_reihe) { std::vector<std::vector<std::string>> csv_daten = leser.erhalteDatenobj(); for (size_t idx = 1; idx < csv_daten.size(); idx++) { // sleep的时候不需要锁,先释放锁让线程二有机会运行 std::this_thread::sleep_for(std::chrono::seconds(sekunden)); // 只在修改共享数据时加锁,修改完成后自动释放锁 std::lock_guard<std::mutex> lck(mtx); csv_reihe = csv_daten[idx]; event_angekommen = true; condVar.notify_one(); } // 所有CSV行处理完毕,通知线程二退出循环 std::lock_guard<std::mutex> lck(mtx); stop_processing = true; condVar.notify_one(); }
修正后的线程二代码
void detektiere_events(Detektion detektion, std::vector<std::string> &csv_reihe, std::vector<std::string> &pir_events) { while(true) { std::cout<<"Warte"<<std::endl; std::unique_lock<std::mutex> lck(mtx); // 等待新数据或者结束信号 condVar.wait(lck, [] {return event_angekommen || stop_processing; }); // 收到结束信号就退出循环 if(stop_processing) { std::cout<<"Verarbeitung beendet."<<std::endl; break; } // 重置事件标志,避免下次wait直接触发(防止重复处理同一行数据) event_angekommen = false; std::cout<<"Detektiere Events"<<std::endl; std::string externes_event_user_id = csv_reihe[4]; std::string externes_event_data = csv_reihe[6]; detektion.neues_event(externes_event_data, externes_event_user_id); if(detektion.pruefe_Pir_id()) { pir_events.push_back(externes_event_data); } } }
关键说明
- 缩小锁的作用范围:线程一只有在更新共享数据和发送通知时才持有锁,sleep期间锁是释放的,线程二可以正常获取锁并等待通知。
- 新增结束标志:当线程一处理完所有CSV行后,通过
stop_processing通知线程二退出循环,避免线程二无限等待。 - 重置事件标志:线程二每次处理完数据后把
event_angekommen设为false,确保下次wait会等待新的通知,不会重复处理同一行数据。
内容的提问来源于stack exchange,提问作者s kop
相关产品推荐
相关产品推荐

