You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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操作可能无法正常完成(因为线程还在跑),存在资源泄漏风险。

修正建议:

  1. 初始化标志位:在构造函数中显式初始化signalScheduleSwitch为false,比如:
    Class(const std::string& s, const int& i) : m_data(s), threadName(i), counter(0), signalScheduleSwitch(false) { }
    
  2. 实现双向同步:新增一个反向标志位(比如readDone),让Write线程等待Read处理完成后再继续执行。这样两个线程才能真正交替运行:
    • Write线程执行完后设置signalScheduleSwitch = true,然后等待readDone变为true。
    • Read线程被唤醒处理完后设置signalScheduleSwitch = false和readDone = true,通知Write线程继续。
  3. 调整notify时机:在修改完标志位后立即调用notify_one,且确保在锁的作用域内或者修改标志位后马上通知,避免延迟导致的多次循环。
  4. 添加终止标志:新增一个std::atomic<bool> stop标志,在析构函数中设置为true,让两个线程的循环能正常退出,确保join成功。

内容的提问来源于stack exchange,提问作者rebelliousconformist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 21:58:09