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