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

如何用条件变量修复电机线程切换中的竞态条件问题?

电机线程与步骤跳转的同步问题修复

问题场景

我有一套多步骤的工艺流程,部分步骤需要控制电机,部分不需要。之前用join()等待电机线程完成后再进入下一步,现在要实现「跳至下一步」功能:点击跳转按钮时,只有下一步包含电机移动操作才需要停止当前电机,否则不能停电机。

为了实现这个逻辑,我用了两个全局标志:threadFinished(电机线程完成时设为true)和signalReceived(收到跳转信号时设为true),但代码存在严重的同步问题:

  1. 第一次迭代(第一步)触发跳转信号,主线程进入第二次迭代;
  2. 第二次迭代刚启动新的电机线程,第一次迭代的电机线程才完成,把全局的threadFinished设为true,导致第二次迭代误以为是自己的电机线程完成,逻辑完全混乱。

原代码如下:

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

std::mutex m;
std::condition_variable cv;
bool signalReceived = false;
bool threadFinished = false;

void moveMotor() {
    // 电机移动逻辑...

    std::lock_guard<std::mutex> lock(m);
    threadFinished = true;
    signalReceived = false;
    cv.notify_one();
}

void signalHandler() {
    std::lock_guard<std::mutex> lock(m);
    signalReceived = true;
    cv.notify_one();
}

int main() {
    while (true) {
        std::thread motorThread(moveMotor);
        motorThread.detach();

        std::unique_lock<std::mutex> lock(m);
        cv.wait(lock, [] { return threadFinished || signalReceived; });

        if (threadFinished) {
            std::cout << "电机线程完成." << std::endl;
        }
        if (signalReceived) {
            std::cout << "收到跳转信号." << std::endl;
        }

        threadFinished = false;
        signalReceived = false;
    }

    return 0;
}

核心问题分析

全局的状态标志threadFinished和signalReceived是所有迭代共享的,而detach()后的电机线程生命周期和主线程迭代完全脱钩——前一个线程的延迟结束会污染当前迭代的状态判断,导致主线程混淆不同线程的完成信号。

修复方案:给每个迭代绑定专属状态

核心思路是让每个迭代的电机线程和主线程使用独立的状态变量,避免跨迭代的状态干扰。可以用智能指针管理每个迭代的状态,保证线程生命周期内状态有效。

修改后的代码

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <memory>
#include <chrono>

// 每个迭代专属的状态结构体
struct StepState {
    std::mutex mutex;
    std::condition_variable cv;
    bool threadFinished = false;
    bool signalReceived = false;
    // 标记当前步骤是否需要电机操作(用于判断是否要停止电机)
    bool needMotor = false;
};

// 全局:当前正在运行的步骤状态(用于信号处理函数访问)
std::shared_ptr<StepState> currentState;
std::mutex globalStateMutex;

void moveMotor(std::shared_ptr<StepState> state) {
    // 模拟电机移动逻辑
    if (state->needMotor) {
        std::cout << "电机开始移动..." << std::endl;
        // 这里替换为实际的电机移动代码
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }

    // 标记当前线程完成
    std::lock_guard<std::mutex> lock(state->mutex);
    state->threadFinished = true;
    state->cv.notify_one();
}

void signalHandler() {
    std::lock_guard<std::mutex> globalLock(globalStateMutex);
    if (currentState) {
        std::lock_guard<std::mutex> lock(currentState->mutex);
        currentState->signalReceived = true;
        currentState->cv.notify_one();
    }
}

int main() {
    // 模拟工艺流程步骤:true表示需要电机操作,false不需要
    bool steps[] = {true, false, true, false};
    int stepIndex = 0;

    while (true) {
        // 创建当前步骤的专属状态
        auto state = std::make_shared<StepState>();
        state->needMotor = steps[stepIndex % 4];
        stepIndex++;

        // 更新全局当前状态(加锁保护)
        {
            std::lock_guard<std::mutex> globalLock(globalStateMutex);
            currentState = state;
        }

        // 启动电机线程(传递当前状态)
        std::thread motorThread(moveMotor, state);
        // 用智能指针保证状态在线程结束前有效,detach后也不会出现悬空指针
        motorThread.detach();

        // 等待当前步骤的状态触发
        std::unique_lock<std::mutex> lock(state->mutex);
        state->cv.wait(lock, [&state] { 
            return state->threadFinished || state->signalReceived; 
        });

        // 处理结果
        if (state->threadFinished) {
            std::cout << "当前步骤电机线程完成,进入下一步." << std::endl;
        }
        if (state->signalReceived) {
            std::cout << "收到跳转信号";
            // 判断下一步是否需要电机操作,决定是否停止当前电机
            bool nextNeedMotor = steps[stepIndex % 4];
            if (nextNeedMotor && state->needMotor) {
                std::cout << ",下一步需要电机,已停止当前电机";
                // 这里添加停止电机的代码
            }
            std::cout << ",进入下一步." << std::endl;
        }

        // 清空全局当前状态(加锁保护)
        {
            std::lock_guard<std::mutex> globalLock(globalStateMutex);
            currentState.reset();
        }
    }

    return 0;
}

关键改进点

  1. 专属状态结构体:每个迭代创建独立的StepState,包含自己的互斥锁、条件变量和状态标志,彻底避免跨迭代的状态干扰。
  2. 全局当前状态指针:用std::shared_ptr管理当前步骤的状态,信号处理函数只能修改当前活跃步骤的状态,不会影响已结束或未开始的步骤。
  3. 电机停止逻辑整合:在收到跳转信号时,根据当前步骤和下一步是否需要电机操作,决定是否执行停止电机的逻辑,符合需求。
  4. 线程生命周期管理:用智能指针保证状态在电机线程运行期间始终有效,避免悬空指针问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 12:10:19