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(); // 异步触发建图优化});
}