返回

std::atomic模板特化:多线程编程的利器

后端

概述

在多线程编程中,共享变量的访问和修改必须是原子的,否则可能会导致数据竞争和程序崩溃。为了解决这个问题,C++提供了std::atomic模板类。std::atomic是一个轻量级的原子类型,允许多个线程同时访问和修改共享变量,而不会产生数据竞争。

std::atomic的语法如下:

template<typename T>
class atomic {
public:
  // 构造函数
  atomic() noexcept;
  atomic(T desired) noexcept;

  // 赋值运算符
  atomic& operator=(T desired) noexcept;

  // 原子操作
  T operator++() noexcept;
  T operator++(int) noexcept;
  T operator--() noexcept;
  T operator--(int) noexcept;

  // 获取和设置值
  T load(memory_order order = memory_order_seq_cst) const noexcept;
  void store(T desired, memory_order order = memory_order_seq_cst) noexcept;

  // 比较和交换
  bool compare_exchange_weak(T& expected, T desired, memory_order success_order = memory_order_seq_cst,
                            memory_order failure_order = memory_order_seq_cst) noexcept;
  bool compare_exchange_strong(T& expected, T desired, memory_order success_order = memory_order_seq_cst,
                             memory_order failure_order = memory_order_seq_cst) noexcept;

  // 原子交换
  T exchange(T desired, memory_order order = memory_order_seq_cst) noexcept;

  // 原子获取并设置
  T fetch_and(T mask, memory_order order = memory_order_seq_cst) noexcept;
  T fetch_or(T mask, memory_order order = memory_order_seq_cst) noexcept;
  T fetch_xor(T mask, memory_order order = memory_order_seq_cst) noexcept;
  T fetch_add(T value, memory_order order = memory_order_seq_cst) noexcept;
  T fetch_sub(T value, memory_order order = memory_order_seq_cst) noexcept;
};

特化

std::atomic模板可以被特化为任何基本类型或用户定义类型。当std::atomic被特化时,它将生成一个新的原子类型,该类型具有与特化的类型相同的行为。

例如,以下代码将std::atomic特化为int类型:

template<>
class atomic<int> {
public:
  // 构造函数
  atomic() noexcept;
  atomic(int desired) noexcept;

  // 赋值运算符
  atomic& operator=(int desired) noexcept;

  // 原子操作
  int operator++() noexcept;
  int operator++(int) noexcept;
  int operator--() noexcept;
  int operator--(int) noexcept;

  // 获取和设置值
  int load(memory_order order = memory_order_seq_cst) const noexcept;
  void store(int desired, memory_order order = memory_order_seq_cst) noexcept;

  // 比较和交换
  bool compare_exchange_weak(int& expected, int desired, memory_order success_order = memory_order_seq_cst,
                            memory_order failure_order = memory_order_seq_cst) noexcept;
  bool compare_exchange_strong(int& expected, int desired, memory_order success_order = memory_order_seq_cst,
                             memory_order failure_order = memory_order_seq_cst) noexcept;

  // 原子交换
  int exchange(int desired, memory_order order = memory_order_seq_cst) noexcept;

  // 原子获取并设置
  int fetch_and(int mask, memory_order order = memory_order_seq_cst) noexcept;
  int fetch_or(int mask, memory_order order = memory_order_seq_cst) noexcept;
  int fetch_xor(int mask, memory_order order = memory_order_seq_cst) noexcept;
  int fetch_add(int value, memory_order order = memory_order_seq_cst) noexcept;
  int fetch_sub(int value, memory_order order = memory_order_seq_cst) noexcept;
};

使用

为了使用std::atomic,您需要先创建一个std::atomic对象。您可以使用std::atomic的构造函数来创建对象,或者使用std::make_sharedstd::atomic<T>来创建一个共享的std::atomic对象。

一旦您创建了一个std::atomic对象,您就可以使用它的成员函数来访问和修改共享变量。例如,以下代码使用std::atomic来实现一个简单的计数器:

#include <atomic>

std::atomic<int> counter;

int main() {
  // 线程1
  for (int i = 0; i < 1000000; i++) {
    counter++;
  }

  // 线程2
  for (int i = 0; i < 1000000; i++) {
    counter++;
  }

  // 打印计数器值
  std::cout << counter << std::endl;

  return 0;
}

优点

std::atomic具有以下优点:

  • 轻量级:std::atomic是一种轻量级的原子类型,它不会对程序的性能造成太大的影响。
  • 安全:std::atomic是线程安全的,它可以保证多个线程同时访问和修改共享变量不会产生数据竞争。
  • 灵活:std::atomic可以被特化为任何基本类型或用户定义类型,这使得它可以广泛地用于各种场景。

缺点

std::atomic也有一些缺点:

  • 性能:std::atomic的性能不如互斥锁。
  • 复杂性:std::atomic的API比较复杂,需要一些时间来学习和掌握。

结论

std::atomic是一种轻量级的原子类型,它允许多个线程同时访问和修改共享变量,而不会产生数据竞争。std::atomic具有安全、灵活等优点,但性能不如互斥锁。在选择使用std::atomic还是互斥锁时,需要权衡两者的优缺点。