C++原子操作详解

发布时间:2023-05-20

一、概述

C原子操作是C 11标准引入的一个新的特性,用于确保多线程环境下的线程安全性。原子操作是一个不可分割的操作,能够确保被多个线程同时访问的变量能够正确地同步。原子操作提供了一种高效的、易用的方式来处理共享数据。

二、原子变量

原子变量是一种特殊类型的变量,多个线程可以同时访问它。原子变量的操作是原子的,即对一个原子变量的操作不可被打断,也不会被其他线程所干扰。C++语言中定义了原子变量类型std::atomic,原子变量的操作可以通过std::atomic<>模板进行实现。

#include <atomic>
std::atomic<int> counter{0}; //定义一个原子变量
counter++; //原子递增操作

以上代码定义了一个原子变量counter,并对其进行了递增的操作。由于递增操作是原子的,因此可以确保在多线程环境下,对counter的递增操作不会被打断。

三、原子操作类型

C++标准库定义了几种常用的原子操作类型,包括:

1. std::memory_order

std::memory_order是一个枚举类型,用于指定内存序(memory order),即原子操作的执行顺序。

enum class memory_order {
    relaxed, //松散的内存模型,不对内存序做任何保证
    consume, //对读操作的顺序做保证,对写操作没有任何保证
    acquire, //对读操作的顺序做保证,对写操作没有任何保证
    release, //对写操作的顺序做保证,对读操作没有任何保证
    acq_rel, //对读/写操作的顺序做保证
    seq_cst  //对读/写操作和其他原子操作的顺序做保证,严格的内存模型
};

2. std::atomic_flag

std::atomic_flag是一个特殊的原子变量类型,只能够进行原子的测试和设置操作。std::atomic_flag类型可以用于实现自旋锁。

#include <atomic>
std::atomic_flag lock = ATOMIC_FLAG_INIT; //初始化std::atomic_flag
lock.test_and_set(); //原子测试并设置操作
lock.clear(); //原子清除操作

3. std::atomic_bool

std::atomic_bool是一个原子布尔变量类型,可以进行原子的加载、存储和交换操作。

#include <atomic>
std::atomic_bool flag{false}; //定义一个std::atomic_bool变量
bool temp = flag.exchange(true); //原子交换操作

4. std::atomic_integral

std::atomic_integral是一个原子整数变量类型,可以进行原子的加载、存储、交换、递增、递减等操作。

#include <atomic>
std::atomic<int> counter{0}; //定义一个std::atomic<int>变量
counter++; //原子递增操作
int temp = counter.fetch_add(10); //原子加法操作,并返回原先的值

四、原子操作的实现原理

原子操作的实现主要依赖于硬件体系结构提供的特殊指令(CPU指令)。这些特殊指令可以确保对共享变量的操作是原子的,即不可分割的,或者是具有一定的同步语义的。 在x86体系结构下,常用的原子操作命令包括:

  • lock cmpxchg:用于原子比较并交换操作
  • lock xchg:用于原子交换操作
  • lock add/sub:用于原子加法/减法操作 当CPU执行原子操作时,它会锁定访问操作的内存位置,并禁止其他CPU修改该位置的值。当原子操作完成后,CPU会释放对该内存位置的锁定,并允许其他CPU修改该位置的值。

五、多线程编程中的原子操作示例

下面的代码示例演示了原子操作在多线程编程中的使用,其中包括std::atomic_bool的测试和设置操作、std::atomic_int的递增操作,以及std::atomic_flag的设置和清除操作。

#include <iostream>
#include <thread>
#include <atomic>
std::atomic_bool flag{false};
std::atomic_flag lock = ATOMIC_FLAG_INIT;
std::atomic_int counter{0};
void thread_func() {
    lock.test_and_set(); //原子测试并设置lock
    if (!flag) {
        flag = true; //原子设置flag
        std::cout << "Thread " << std::this_thread::get_id() << " sets the flag." << std::endl;
    }
    lock.clear(); //原子清除lock
    counter++; //原子递增
    std::cout << "Thread " << std::this_thread::get_id() << " increases the counter to " << counter << "." << std::endl;
}
int main() {
    std::thread t1(thread_func);
    std::thread t2(thread_func);
    t1.join();
    t2.join();
    return 0;
}

运行该程序,可以看到两个线程分别进行了原子操作,并保证了线程安全。

六、总结

本文对C++原子操作进行了详细的介绍,包括原子变量、原子操作类型、原子操作的实现原理以及在多线程编程中的应用。借助于原子操作,程序员可以轻松地处理共享数据的同步,从而提高程序的并发性能。