通知图标

欢迎访问津桥芝士站

atomic:std::atomic_fetch_add和std::atomic_fetch_add_explicit

来自AI助手的总结
本文探讨了C++标准库中的原子加法函数std::atomic_fetch_add和std::atomic_fetch_add_explicit,强调其在多线程编程中确保数据一致性和线程安全的重要性。

引入

在多线程编程中,安全地对共享资源进行操作至关重要。为此,C++标准库的<atomic>头文件提供了std::atomic_fetch_addstd::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_relaxedmemory_order_acquirememory_order_releasememory_order_acq_relmemory_order_seq_cst

完整示例代码

以下示例展示了如何使用std::atomic_fetch_addstd::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_addstd::atomic_fetch_add_explicit对共享计数器进行原子加法操作。

  1. 创建原子变量

    • std::atomic<int> sharedCounter{0}; 声明一个初始值为0的原子整数变量,用于在多个线程之间共享。
  2. 增量线程

    • incrementer函数中,通过 std::atomic_fetch_add(sharedCounter, 1) 对 sharedCounter 执行递增操作,并返回递增前的值,确保操作的原子性。
  3. 增量线程(显式内存序)

    • 在 incrementerExplicit 函数中,使用 std::atomic_fetch_add_explicit(sharedCounter, 1, std::memory_order_seq_cst) 指定内存序为 memory_order_seq_cst。虽然在此例中较为简单,其灵活性允许在复杂情况下应用不同的内存顺序。
  4. 主函数

    • 在 main 函数中,通过循环创建5个线程,奇偶线程分别调用不同的加法函数,展示两种操作的并发执行并待所有线程结束。
  5. 最终计数显示

    • 主线程最终输出sharedCounter的值,展示这5个线程安全并发增量的结果。

适用场景分析

std::atomic_fetch_add和std::atomic_fetch_add_explicit的应用场景包括:

  1. 线程安全的计数器:多线程环境下共享计数器的安全更新,比如用于多线程任务完成统计。

  2. 无锁数据结构:在构建高效的并发数据结构时,如先进先出(FIFO)或先进后出(LIFO)队列中,加法操作可以帮助减少阻塞和提升性能。

  3. 工作调度和任务分配:原子加法可以用于调度器在多线程中的工作分配,以确保并发工作正确执行。

总结

std::atomic_fetch_addstd::atomic_fetch_add_explicit是C++标准库中强大的原子操作,确保了多线程编程中的数据一致性和线程安全。通过本文的示例,展示了这两个函数的有效使用方式以及在并发程序中的重要性。掌握这些原子操作将帮助开发者设计更高效、更可靠的多线程程序,提升工业软件的质量和性能。

请登录后发表评论

    没有回复内容

正在唤醒异次元光景……