C++双线程打印向量奇偶元素程序无输出且死锁问题排查
多线程打印奇偶元素程序挂起问题排查与修复
问题场景
面试要求实现C++程序,启动两个线程处理输入vector:一个线程打印偶数,另一个打印奇数。以下是原实现代码,但程序无输出且无限挂起:
std::mutex mu_vec; std::condition_variable m_cv; bool odd = true; void print_odd(const std::vector<int>& vals, int &id){ while(true){ std::unique_lock sl(mu_vec); m_cv.wait(sl, []{return odd; }); if(id >= vals.size()){ sl.unlock(); break; } if(vals[id] & 1){ std::cout << vals[id] << "\t"; id++; } else{ odd = false; sl.unlock(); m_cv.notify_one(); } } } void print_even(const std::vector<int>& vals, int &id){ while(true){ std::unique_lock sl(mu_vec); m_cv.wait(sl, []{return !odd; }); if(id >= vals.size()){ sl.unlock(); break; } if((vals[id] & 1) == 0){ std::cout << vals[id] << "\t"; id++; } else{ odd = true; sl.unlock(); m_cv.notify_one(); } } } int main(){ std::vector<int> vals{5, 10, 4, 7, 1, 6}; int id = 0; std::jthread odd_printer(print_odd, std::cref(vals), std::ref(id)); std::jthread eve_printer(print_even, std::cref(vals), std::ref(id)); return 0; }
问题根源
- 处理符合条件元素后无线程切换逻辑:比如奇数线程打印完奇数并
id++后,没有切换odd标志位,也没有通知偶数线程,导致两个线程都进入等待状态。 - 锁操作冗余且错误:手动调用
sl.unlock()会导致unique_lock后续行为异常,因为unique_lock本身会在作用域结束时自动释放锁。 - 线程退出未通知对方:当
id超出vector长度时,当前线程直接退出,但未通知另一个线程,导致对方一直阻塞在wait,无法退出。
修复后的代码
#include <iostream> #include <vector> #include <thread> #include <mutex> #include <condition_variable> std::mutex mu_vec; std::condition_variable m_cv; bool odd_turn = true; // 标记当前是否轮到奇数线程执行 void print_odd(const std::vector<int>& vals, int &id){ while(true){ std::unique_lock<std::mutex> sl(mu_vec); // 等待轮到奇数线程,或id已超出范围 m_cv.wait(sl, []{return odd_turn || id >= vals.size(); }); if(id >= vals.size()){ // 通知偶数线程退出 odd_turn = false; m_cv.notify_one(); break; } if(vals[id] & 1){ std::cout << vals[id] << "\t"; id++; // 切换到偶数线程 odd_turn = false; m_cv.notify_one(); } else { // 当前元素是偶数,切换到偶数线程 odd_turn = false; m_cv.notify_one(); } // unique_lock自动释放锁 } } void print_even(const std::vector<int>& vals, int &id){ while(true){ std::unique_lock<std::mutex> sl(mu_vec); // 等待轮到偶数线程,或id已超出范围 m_cv.wait(sl, []{return !odd_turn || id >= vals.size(); }); if(id >= vals.size()){ // 通知奇数线程退出 odd_turn = true; m_cv.notify_one(); break; } if((vals[id] & 1) == 0){ std::cout << vals[id] << "\t"; id++; // 切换到奇数线程 odd_turn = true; m_cv.notify_one(); } else { // 当前元素是奇数,切换到奇数线程 odd_turn = true; m_cv.notify_one(); } // unique_lock自动释放锁 } } int main(){ std::vector<int> vals{5, 10, 4, 7, 1, 6}; int id = 0; std::jthread odd_printer(print_odd, std::cref(vals), std::ref(id)); std::jthread eve_printer(print_even, std::cref(vals), std::ref(id)); // 等待线程结束,jthread会自动join,这里加换行让输出更整洁 std::cout << std::endl; return 0; }
关键修改说明
- 移除手动
unlock调用,依赖unique_lock的自动释放机制,避免锁状态混乱。 - 无论当前线程是否处理了元素,都要切换
odd_turn标志并通知对方线程,确保线程交替执行。 - 当
id超出vector长度时,设置标志并通知对方线程,让对方能检测到退出条件并终止。 - 调整wait的条件,加入
id >= vals.size(),确保线程能在退出条件满足时被唤醒。
内容的提问来源于stack exchange,提问作者wwite
相关产品推荐
相关产品推荐

