C++中std::atomic_bool详解和实战示例

发布于:2025-07-03 ⋅ 阅读:(18) ⋅ 点赞:(0)

std::atomic_bool 是 C++ 标准库中提供的一种 原子类型,用于在多线程环境下对布尔值进行 线程安全的读写操作,避免使用 std::mutex 带来的性能开销。


1. 基本作用

在多线程环境中,多个线程同时访问一个 bool 类型变量可能会出现 竞态条件(race condition)。使用 std::atomic_bool 可以确保:

  • 每次读取和写入都是 原子性的
  • 不需要手动加锁;
  • 性能比 std::mutex 更好,适用于控制标志位等简单变量。

2. 常用操作

操作 说明
load() 原子读取值
store(true/false) 原子写入值
exchange(value) 原子地将值替换为 value 并返回旧值
compare_exchange_weak 原子比较并条件赋值(弱)
compare_exchange_strong 原子比较并条件赋值(强)

3. 示例代码:线程安全的停止标志

#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>

std::atomic_bool stop_flag(false);

void worker_thread() {
    std::cout << "Worker thread started.\n";
    while (!stop_flag.load()) {
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        std::cout << "Working...\n";
    }
    std::cout << "Worker thread stopping.\n";
}

int main() {
    std::thread t(worker_thread);

    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "Main thread: stopping worker.\n";
    stop_flag.store(true); // 原子写入,通知线程退出

    t.join();
    std::cout << "Main thread: done.\n";
    return 0;
}

4. exchange() 用法示例

std::atomic_bool flag(false);

// 原子地将 flag 设置为 true,并获取旧值
bool was_set = flag.exchange(true);
if (!was_set) {
    std::cout << "First time setting flag!\n";
} else {
    std::cout << "Flag was already set.\n";
}

5. compare_exchange_strong() 用法示例

std::atomic_bool ready(false);
bool expected = false;

if (ready.compare_exchange_strong(expected, true)) {
    std::cout << "We changed it from false to true.\n";
} else {
    std::cout << "It was already true.\n";
}

compare_exchange_strong(expected, new_val) 的意思是:

  • 如果当前值 == expected,则原子地赋值为 new_val,并返回 true
  • 否则返回 false,且 expected 被更新为当前值。

6. 和 volatile 的区别?

项目 std::atomic volatile
原子性保证
线程安全
用于多线程 ❌(不适用)

7. 典型应用场景

  • 线程停止标志(如 kill_switch, terminate_flag
  • 单次初始化控制(once_flag 替代方案)
  • 简单信号通信(如触发事件)

8. 实战应用示例

在建图(SLAM)系统中,std::atomic_bool 通常用于 线程控制标志,以线程安全方式实现异步逻辑的终止、控制或状态指示。以下是详细用途、使用示例,以及与建图模块结合的典型场景。


建图系统中常见使用场景

变量名 类型 作用说明
kill_switch std::atomic_bool 强制立即终止后端建图线程
end_of_sequence std::atomic_bool 等待数据队列处理完后自动终止线程
request_to_optimize std::atomic_bool 请求触发一次后端优化
request_to_recover std::atomic_bool 请求重新恢复全局状态或轨迹
is_mapping std::atomic_bool 指示建图线程当前是否运行中
has_new_data std::atomic_bool 用于触发新数据到来时的条件变量唤醒

建图线程中的使用示例

class AsyncMapping {
public:
  AsyncMapping() : kill_switch(false), end_of_sequence(false), request_to_optimize(false) {
    mapping_thread = std::thread(&AsyncMapping::run, this);
  }

  ~AsyncMapping() {
    kill_switch.store(true);         // 强制中断
    condition.notify_all();
    if (mapping_thread.joinable()) mapping_thread.join();
  }

  void insert_submap(const SubMap::Ptr& submap) {
    {
      std::lock_guard<std::mutex> lock(queue_mutex);
      submap_queue.push(submap);
    }
    request_to_optimize.store(true);
    condition.notify_one(); // 唤醒线程
  }

private:
  void run() {
    while (!kill_switch.load()) {
      std::unique_lock<std::mutex> lock(queue_mutex);
      condition.wait(lock, [&]() {
        return kill_switch.load() || !submap_queue.empty() || request_to_optimize.load();
      });

      if (kill_switch.load()) break;

      // 处理队列
      while (!submap_queue.empty()) {
        auto submap = submap_queue.front();
        submap_queue.pop();
        process_submap(submap);
      }

      if (request_to_optimize.exchange(false)) {
        optimize(); // 执行一次后端优化
      }
    }
  }

  void process_submap(const SubMap::Ptr& submap);
  void optimize();

private:
  std::atomic_bool kill_switch;
  std::atomic_bool end_of_sequence;
  std::atomic_bool request_to_optimize;

  std::queue<SubMap::Ptr> submap_queue;
  std::mutex queue_mutex;
  std::condition_variable condition;

  std::thread mapping_thread;
};

** 技巧说明**

  • atomic_bool + condition_variable 是建图线程中典型的等待-通知机制组合。
  • exchange(false) 常用于“消费型”标志,即只触发一次(如 request_to_optimize)。
  • 在析构时使用 kill_switch 可以 无锁安全终止线程,无需强行 detach

推荐命名规范

标志变量 推荐用途
kill_switch 强制立即终止所有建图处理
optimization_flag 表示优化请求
data_ready 数据队列中是否有数据可处理
map_updated 是否生成新地图输出
need_save 是否需要保存地图(外部触发)

如果使用 ThreadPool + std::future,也可以这样结合:

if (request_to_optimize.exchange(false)) {
  thread_pool.submit([this]() {
    global_mapping->optimize();  // 异步触发建图优化
  });
}


网站公告

今日签到

点亮在社区的每一天
去签到