使用Mutex与Condition Variable的C++线程同步问题排查
双线程同步实现的问题与误区分析
我用mutex和条件变量写了一段C++代码,想通过条件变量等待标志位设为true来实现双线程切换,但始终没法得到规整的线程调度。请问我的实现思路是不是有问题?
我的代码:
#include <thread> #include <string> #include <iostream> #include <mutex> #include <condition_variable> #include "signal.h" #include <atomic> class Class { public: Class(const std::string& s, const int& i) : m_data(s), threadName(i),counter(0) { } ~Class() { if (m_thread.joinable()) { m_thread.join(); } if (m_thread2.joinable()){ m_thread2.join(); } std::cout << "destructor called" << std::endl; } void runThread() { m_thread = std::thread(&Class::printThreadWrite, this); m_thread2 = std::thread(&Class::printThreadRead,this); } private: std::mutex m_printmutex; std::condition_variable m_conditionvar; std::string m_data; std::thread m_thread; std::thread m_thread2; std::atomic<bool> signalScheduleSwitch; int threadName; std::atomic<int> counter; void printThreadWrite() { while(1){ { std::lock_guard<std::mutex> lg(m_printmutex); std::cout << "thread # " << std::this_thread::get_id() << " " << m_data << '\n'; counter ++; signalScheduleSwitch = true; } std::this_thread::sleep_for(std::chrono::milliseconds(2)); m_conditionvar.notify_one(); } } void printThreadRead() { while (1) { std::unique_lock<std::mutex> uLock(m_printmutex); m_conditionvar.wait(uLock,[this](){ return signalScheduleSwitch == true;}); std::cout << "counter value is:" << counter << "\n"; signalScheduleSwitch = false; } } }; void signalHandler(int s){ printf("caught signal %d Exiting\n", s); exit(1); } int main(int argc, char** argv) { signal(SIGINT, signalHandler); try { Class c("Hello, world!",1); c.runThread(); } catch(const std::exception& e) { std::cerr << e.what() << '\n'; } return 0; }
核心误区分析:
- 未初始化标志位:
signalScheduleSwitch是std::atomic<bool>类型的类成员,默认不会自动初始化为false,其初始值未定义。这会导致printThreadRead启动时可能直接跳过wait逻辑,或者出现不可预期的唤醒行为。 - 单向通知,无反向同步:当前逻辑只有Write线程通知Read线程,Read线程处理完后没有通知Write线程继续执行。Write线程会无限制快速循环,即使Read还没处理完上一次的信号,Write已经多次修改
counter和signalScheduleSwitch,导致Read线程被频繁唤醒,输出混乱。 - notify时机错误:Write线程在释放锁并sleep之后才调用
notify_one,这期间Write线程可能已经进入下一轮循环再次获取锁,多次设置signalScheduleSwitch = true。这种情况下,Read线程一次唤醒可能对应Write的多次执行,完全达不到“交替执行”的效果。 - 缺少终止逻辑:两个线程都是无限循环,即使主程序收到信号退出,
join操作可能无法正常完成(因为线程还在跑),存在资源泄漏风险。
修正建议:
- 初始化标志位:在构造函数中显式初始化
signalScheduleSwitch为false,比如:Class(const std::string& s, const int& i) : m_data(s), threadName(i), counter(0), signalScheduleSwitch(false) { } - 实现双向同步:新增一个反向标志位(比如
readDone),让Write线程等待Read处理完成后再继续执行。这样两个线程才能真正交替运行:- Write线程执行完后设置
signalScheduleSwitch = true,然后等待readDone变为true。 - Read线程被唤醒处理完后设置
signalScheduleSwitch = false和readDone = true,通知Write线程继续。
- Write线程执行完后设置
- 调整notify时机:在修改完标志位后立即调用
notify_one,且确保在锁的作用域内或者修改标志位后马上通知,避免延迟导致的多次循环。 - 添加终止标志:新增一个
std::atomic<bool> stop标志,在析构函数中设置为true,让两个线程的循环能正常退出,确保join成功。
内容的提问来源于stack exchange,提问作者rebelliousconformist
相关产品推荐
相关产品推荐

