如何用条件变量修复电机线程切换中的竞态条件问题?
电机线程与步骤跳转的同步问题修复
问题场景
我有一套多步骤的工艺流程,部分步骤需要控制电机,部分不需要。之前用join()等待电机线程完成后再进入下一步,现在要实现「跳至下一步」功能:点击跳转按钮时,只有下一步包含电机移动操作才需要停止当前电机,否则不能停电机。
为了实现这个逻辑,我用了两个全局标志:threadFinished(电机线程完成时设为true)和signalReceived(收到跳转信号时设为true),但代码存在严重的同步问题:
- 第一次迭代(第一步)触发跳转信号,主线程进入第二次迭代;
- 第二次迭代刚启动新的电机线程,第一次迭代的电机线程才完成,把全局的
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; }
关键改进点
- 专属状态结构体:每个迭代创建独立的
StepState,包含自己的互斥锁、条件变量和状态标志,彻底避免跨迭代的状态干扰。 - 全局当前状态指针:用
std::shared_ptr管理当前步骤的状态,信号处理函数只能修改当前活跃步骤的状态,不会影响已结束或未开始的步骤。 - 电机停止逻辑整合:在收到跳转信号时,根据当前步骤和下一步是否需要电机操作,决定是否执行停止电机的逻辑,符合需求。
- 线程生命周期管理:用智能指针保证状态在电机线程运行期间始终有效,避免悬空指针问题。
内容的提问来源于stack exchange,提问作者asdfasdf
相关产品推荐
相关产品推荐

