引入
在多线程编程中,安全地对共享资源进行操作至关重要。为此,C++标准库的<atomic>头文件提供了std::atomic_fetch_add和std::atomic_fetch_add_explicit这两个函数,用于实现原子加法操作。这两个函数允许在多线程环境中安全地对原子变量进行加法运算,同时返回之前的值,确保线程间不发生数据竞争和不一致性。通过使用这些原子操作,开发者可以高效可靠地管理共享资源。本文将深入探讨这两个函数的特性、用法、完整示例代码及其适用场景分析。
特性/函数/功能语法介绍
std::atomic_fetch_add
std::atomic_fetch_add的主要特性包括:
- 原子性:保证在多个线程对同一变量进行加法操作时不会出现数据竞争。
- 简便性:提供直观易用的接口,方便直接对原子变量进行加法操作。
语法
#include <atomic>
T std::atomic_fetch_add(std::atomic<T>& obj, T arg);
std::atomic_fetch_add_explicit
std::atomic_fetch_add_explicit的主要特性包括:
- 内存序控制:允许开发者指定内存序,从而增强对操作行为的灵活掌控。
- 更广的适用性:适用于需要特定内存顺序约束的高性能场景。
语法
#include <atomic>
T std::atomic_fetch_add_explicit(std::atomic<T>& obj, T arg, std::memory_order order);
参数order可以是:memory_order_relaxed、memory_order_acquire、memory_order_release、memory_order_acq_rel和memory_order_seq_cst。
完整示例代码
以下示例展示了如何使用std::atomic_fetch_add和std::atomic_fetch_add_explicit来对共享变量进行原子加法操作:
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>
std::atomic<int> sharedCounter{0}; // 创建原子变量
void incrementer(int id) {
for (int i = 0; i < 5; ++i) {
int oldValue = std::atomic_fetch_add(sharedCounter, 1); // 使用atomic_fetch_add
std::cout << "Thread " << id << " incremented counter from " << oldValue << " to " << oldValue + 1 << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void incrementerExplicit(int id) {
for (int i = 0; i < 5; ++i) {
int oldValue = std::atomic_fetch_add_explicit(sharedCounter, 1, std::memory_order_seq_cst); // 使用atomic_fetch_add_explicit
std::cout << "Thread " << id << " incremented (explicit) counter from " << oldValue << " to " << oldValue + 1 << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
int main() {
std::thread threads[5];
// 创建线程使用不同的加法函数
for (int i = 0; i < 5; ++i) {
if (i % 2 == 0) {
threads[i] = std::thread(incrementer, i);
} else {
threads[i] = std::thread(incrementerExplicit, i);
}
}
// 等待所有线程完成
for (auto& th : threads) {
th.join();
}
std::cout << "Final counter value: " << sharedCounter.load() << std::endl;
return 0;
}
代码解析
在上述示例中,我们展示了如何利用std::atomic_fetch_add和std::atomic_fetch_add_explicit对共享计数器进行原子加法操作。
-
创建原子变量:
std::atomic<int> sharedCounter{0};声明一个初始值为0的原子整数变量,用于在多个线程之间共享。
-
增量线程:
- 在
incrementer函数中,通过std::atomic_fetch_add(sharedCounter, 1)对sharedCounter执行递增操作,并返回递增前的值,确保操作的原子性。
- 在
-
增量线程(显式内存序):
- 在
incrementerExplicit函数中,使用std::atomic_fetch_add_explicit(sharedCounter, 1, std::memory_order_seq_cst)指定内存序为memory_order_seq_cst。虽然在此例中较为简单,其灵活性允许在复杂情况下应用不同的内存顺序。
- 在
-
主函数:
- 在
main函数中,通过循环创建5个线程,奇偶线程分别调用不同的加法函数,展示两种操作的并发执行并待所有线程结束。
- 在
-
最终计数显示:
- 主线程最终输出
sharedCounter的值,展示这5个线程安全并发增量的结果。
- 主线程最终输出
适用场景分析
std::atomic_fetch_add和std::atomic_fetch_add_explicit的应用场景包括:
-
线程安全的计数器:多线程环境下共享计数器的安全更新,比如用于多线程任务完成统计。
-
无锁数据结构:在构建高效的并发数据结构时,如先进先出(FIFO)或先进后出(LIFO)队列中,加法操作可以帮助减少阻塞和提升性能。
-
工作调度和任务分配:原子加法可以用于调度器在多线程中的工作分配,以确保并发工作正确执行。
总结
std::atomic_fetch_add和std::atomic_fetch_add_explicit是C++标准库中强大的原子操作,确保了多线程编程中的数据一致性和线程安全。通过本文的示例,展示了这两个函数的有效使用方式以及在并发程序中的重要性。掌握这些原子操作将帮助开发者设计更高效、更可靠的多线程程序,提升工业软件的质量和性能。



没有回复内容