多线程抢占长运行方法的线程安全实现方案咨询
C++线程安全解决方案:确保halt()正确中断或阻止executeInSeparateThread()
核心思路
要解决这个问题,关键是原子化控制runForAwhile()的启动时机,同时保证stopRunner()只在runForAwhile()运行时生效,或者彻底阻止runForAwhile()启动。通过原子状态变量结合原子操作实现线程安全的状态流转,避免竞态条件。
具体实现步骤
- 定义原子状态变量:用枚举标记当前执行状态,确保线程间状态可见性。
- 控制
runForAwhile()启动:完成前置操作后,通过原子操作尝试切换状态为“运行中”,仅切换成功才启动任务。 halt()分支处理:根据当前状态,要么阻止任务启动,要么调用stopRunner()中断运行中的任务。- 前置操作插入检查(可选):若
doBeforeThings()耗时较长,可在其中加入状态检查,提前响应halt请求。
完整代码示例
#include <atomic> // 实际对应moveit::task_constructor::Task class LongRunner { public: void runForAwhile(); // 仅在runForAwhile运行时生效的中断方法 void stopRunner(); }; // 实际对应BT::ThreadedAction class ExecutionBase { public: virtual void executeInSeparateThread() = 0; // 等待执行线程结束,可重写做清理 virtual void halt() = 0; }; enum class ExecutionState { IDLE, // 未启动runForAwhile RUNNING, // runForAwhile正在执行 HALTED // 已收到halt请求 }; class MyExecution : public ExecutionBase { public: void executeInSeparateThread() override { doBeforeThings(); // 原子操作:尝试将状态从IDLE改为RUNNING,避免竞态 ExecutionState expected = ExecutionState::IDLE; if (state_.compare_exchange_strong(expected, ExecutionState::RUNNING)) { long_runner_.runForAwhile(); // 任务正常完成,恢复IDLE状态 state_.store(ExecutionState::IDLE); } doAfterThings(); } void halt() override { ExecutionState expected = ExecutionState::IDLE; // 尝试将状态改为HALTED,如果当前是IDLE,说明runForAwhile还没启动 if (state_.compare_exchange_strong(expected, ExecutionState::HALTED)) { // 无需调用stopRunner,直接阻止runForAwhile启动 } else if (expected == ExecutionState::RUNNING) { // runForAwhile正在运行,调用stopRunner中断 long_runner_.stopRunner(); // 将状态标记为HALTED state_.store(ExecutionState::HALTED); } // 状态已为HALTED时无需操作 // 调用基类方法等待线程结束 ExecutionBase::halt(); } private: void doBeforeThings() { // 如果此方法耗时较长,可插入状态检查提前退出 for (int i = 0; i < 10; ++i) { // 执行部分前置工作 if (state_.load() == ExecutionState::HALTED) { return; } } } void doAfterThings() { // 执行后置清理工作 } LongRunner long_runner_; std::atomic<ExecutionState> state_{ExecutionState::IDLE}; };
关键细节说明
- 原子状态操作:
compare_exchange_strong是原子操作,确保“检查状态+修改状态”的操作不会被其他线程打断,彻底避免“检查后状态被修改”的竞态条件。 - 内存可见性:
std::atomic默认使用memory_order_seq_cst内存顺序,保证所有线程能看到最新的状态值,无需额外互斥锁。 - 兼容第三方库:完全不需要修改
LongRunner和ExecutionBase的代码,仅在派生类中添加同步逻辑,符合约束要求。
内容的提问来源于stack exchange,提问作者mrjogo
相关产品推荐
相关产品推荐

