ZBLOG

C++ atomic

在C++中,std::atomic 是一个用于实现原子操作的模板类,它允许你在多线程环境中安全地访问和修改共享数据,而无需使用传统的互斥锁。这使得程序可以避免由于锁竞争引起的性能瓶颇,同时保证数据的一致性。

1. 基本概念

原子性:指对变量的操作是不可分割的。即使多个线程同时访问该变量,也不会导致状态不一致。

原子操作:这些操作要么完全成功,要么完全失败,不会出现中间状态。例如,增加一个整数的值就是一个典型的原子操作。

2. 使用 std::atomic

包含头文件

要使用 std::atomic,你需要包含 <atomic> 头文件:

#include <atomic>

定义原子变量

你可以定义不同类型的原子变量,例如整型、布尔型等:

std::atomic<int> atomicInt(0);
std::atomic<bool> atomicBool(false);

常用成员函数

  • load(): 原子读取当前值。

    int value = atomicInt.load(); // 获取当前值
    
  • store(): 原子写入一个新值。

    atomicInt.store(5); // 设置为 5
    
  • exchange(): 原子替换当前值,并返回旧值。

    int oldValue = atomicInt.exchange(10); // 设置为 10,并获取旧值
    
  • fetch_add() / fetch_sub(): 原子的加法或减法运算,并返回结果之前的值。

    int newValue = atomicInt.fetch_add(1); // 将其增加 1,返回增加前的值
    
  • compare_exchange_weak / compare_exchange_strong: 比较并交换,如果当前值与预期相等则设置为新值,这两个函数具有轻微区别。通常用于实现更复杂的数据结构,如无锁队列等。

3. 示例代码

以下是一个简单示例,展示了如何使用 std::atomic 来确保在多线程环境中的安全性:

#include <iostream>
#include <thread>
#include <vector>
#include <atomic>

std::atomic<int> counter(0);

void increment(int times) {
    for (int i = 0; i < times; ++i) {
        counter.fetch_add(1); // 安全递增计数器
    }
}

int main() {
    const int numThreads = 10;
    const int incrementsPerThread = 1000;
    
    std::vector<std::thread> threads;

    // 启动多个线程来增加计数器
    for (int i = 0; i < numThreads; ++i) {
        threads.emplace_back(increment, incrementsPerThread);
    }

    // 等待所有线程完成工作
    for (auto& t : threads) {
        t.join();
    }

    std::cout << "Final counter value: " << counter.load() << std::endl;

    return 0;
}

4. 内存顺序

std::atomic 在 C++11 引入后,可以指定内存顺序(memory order)以控制操作之间的可见性。这对于优化和确保正确性非常重要。常用内存顺序包括:

  • memory_order_relaxed: 不提供同步或顺序保证,只保证原子性。

  • memory_order_acquire: 确保该读取之前所有写入都已完成。

  • memory_order_release: 确保该写入之后所有读取都能看到此写入之前的数据。

  • memory_order_acq_rel: 同时提供 acquire 和 release 的效果。

  • memory_order_seq_cst: 默认选项,表示严格按照程序中的出现顺序处理原子操作。

例如,你可以在调用时指定内存顺序:

counter.fetch_add(1, std::memory_order_relaxed);

总结

使用 std::atomic 提供了一种方便、安全的方法来处理多线程编程中的共享数据,通过它能够提高程序性能,同时避免死锁和竞争条件。理解其基本概念、常用方法及内存顺序将有助于开发高效且安全的并发应用程序。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=20585

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?