C++ std::atomic 原子操作介绍
std::atomic 是 C++11 引入的一个模板类,用于提供对单个变量或对象进行原子操作的能力。原子操作是不可分割的,即操作在执行过程中不会被线程调度机制中断。这对于多线程编程中的同步和数据一致性至关重要。
std::atomic 可以应用于基本数据类型(如 bool、int、float 等)以及用户自定义类型(需要满足特定的条件)。std::atomic 提供了多种成员函数,如 load()、store()、exchange()、compare_exchange_weak()、compare_exchange_strong()、fetch_add()、fetch_sub() 等,用于执行各种原子操作。
原子操作的使用场景
- 无锁编程:在多线程程序中,使用 std::atomic 可以避免使用互斥锁(std::mutex)等同步机制,从而减少上下文切换和锁竞争的开销。
- 计数器:实现线程安全的计数器,如统计某个操作的执行次数。
- 标志位:用于控制线程的执行流程,如设置完成标志、停止标志等。
- 状态变量:保护共享状态变量,确保该状态变量在多线程环境下的一致性和可见性。
以下给出二个原子操作的使用示例。
示例 1:原子计数器
#include <iostream>
#include <thread>
#include <vector>
#include <atomic>
std::atomic<int> g_counter(0);
void increment(int n) {
for (int i = 0; i < n; ++i) {
g_counter.fetch_add(1, std::memory_order_relaxed);
}
}
int main() {
const int num_threads = 10;
const int iterations = 1000;
std::vector<std::thread> threads;
for (int i = 0; i < num_threads; ++i) {
threads.emplace_back(increment, iterations);
}
for (auto& t : threads) {
t.join();
}
std::cout << "Final counter value: " << g_counter << std::endl;
return 0;
}
在这个例子中,我们创建了一个原子计数器 g_counter,并启动了多个线程去增加它的值。每个线程都执行了 increment 函数,该函数通过 fetch_add 方法以原子方式增加计数器的值。
最后,等待所有线程完成,并打印出计数器 g_counter 的最终结果值。
示例 2:使用 compare_exchange_weak 实现自旋锁
#include <iostream>
#include <thread>
#include <atomic>
std::atomic<bool> g_lock(false);
void critical_section() {
bool expected = false;
while (!g_lock.compare_exchange_weak(expected, true, std::memory_order_acquire)) {
expected = false;
}
// 临界区代码
std::cout << "Entered critical section by thread " << std::this_thread::get_id() << std::endl;
// 释放锁
g_lock.store(false, std::memory_order_release);
}
int main() {
std::thread t1(critical_section);
std::thread t2(critical_section);
t1.join();
t2.join();
return 0;
}
在这个例子中,我们使用 std::atomic 类型的 g_lock 变量来实现一个简单的自旋锁。
compare_exchange_weak 方法尝试将 lock 的值从 expected(预期值)更改为 true(锁定状态),如果 g_lock 的当前值等于 expected,则操作成功,线程进入临界区;否则,循环重试。需要注意一点,compare_exchange_weak 可能由于伪失败(spurious failure)而失败,即使没有其他线程修改 g_lock 的值,因此通常需要在循环中重试,确保最终操作成功。
最后,在临界区执行完毕后,通过 store 方法将 g_lock 设置为 false,释放锁。
-End-
#想了解更多精彩内容,关注下方公众号。
本人开发小杨哥:
超20年C++开发经验,独立软件开发。著名开源产品MYCP(高并发C++通信应用服务器)作者,和WordBN字远笔记共享软件产品作者。
长期招C++、Qt编程学员,欢迎加好友咨询。