2023年11月19日

[C++] Atomic


缘由

在需要进行并发编程的多线程应用中,std::atomic会被广泛使用。

用法

  • load():从原子对象中加载当前值。
#include <iostream>
#include <atomic>
int main() {
std::atomic<int> value(10);
int loadedValue = value.load();
std::cout << "Loaded value: " << loadedValue << std::endl;
return 0;
}
  • store(val):将给定的值存储到原子对象中。
#include <iostream>
#include <atomic>
int main() {
std::atomic<int> value;
value.store(20);
std::cout << "Stored value: " << value << std::endl;
return 0;
}
  • exchange(val):交换原子对象中的值,并返回之前的值
#include <iostream>
#include <atomic>
int main() {
std::atomic<int> value(30);
int oldValue = value.exchange(40);
std::cout << "Exchanged value: " << oldValue << std::endl;
std::cout << "New value: " << value << std::endl;
return 0;
}
  • compare_exchange_weak(expected, desired) 和 compare_exchange_strong(expected, desired):比较原子对象的当前值和期望值,如果相等则用新值替换当前值。
#include <iostream>
#include <atomic>
int main() {
std::atomic<int> value(50);
int expected = 50;
int desired = 60;
bool success = value.compare_exchange_weak(expected, desired);
if (success) {
std::cout << "Compare_exchange successful. New value: " << value << std::endl;
} else {
std::cout << "Compare_exchange failed. Current value: " << value << std::endl;
}
return 0;
}
  1. fetch_add(val) 和 fetch_sub(val):分别对原子对象的值进行加法和减法操作,并返回操作之前的值。
#include <iostream>
#include <atomic>
int main() {
std::atomic<int> value(70);
int oldValue = value.fetch_add(5);
std::cout << "Old value: " << oldValue << std::endl;
std::cout << "New value: " << value << std::endl;
return 0;
}
  1. fetch_and(val)fetch_or(val) 和 fetch_xor(val):分别对原子对象的值进行按位与、按位或和按位异或操作,并返回操作之前的值。
#include <iostream>
#include <atomic>
int main() {
std::atomic<int> value(15);
int oldValue = value.fetch_and(3);
std::cout << "Old value: " << oldValue << std::endl;
std::cout << "New value: " << value << std::endl;
return 0;
}

作用

  1. 保证原子性操作std::atomic 可以确保基本的内存读取、写入和其他操作是原子的,这意味着在多线程环境下,对 std::atomic 类型的对象进行操作时不会发生数据竞争,从而避免了需要额外的锁来保护这些操作的情况。

  2. 提供内存顺序保证std::atomic 也提供了内存顺序保证,确保所有线程都能够看到相同的操作顺序,从而避免了由于指令重排等导致的意外行为。

  3. 用于并发数据结构std::atomic 在开发并发数据结构时非常有用,比如并发队列、栈、哈希表等,它可以确保在多线程环境下对这些数据结构的操作是线程安全的。最好还是用lock_guard搭配mutex来处理vector等STL容器。

  4. 提高性能:相比使用锁(如互斥锁)来进行同步,std::atomic 可能在某些情况下具有更好的性能,特别是对于一些简单的操作,因为它们不涉及线程的阻塞和唤醒。