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;}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;}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;}作用
-
保证原子性操作:
std::atomic可以确保基本的内存读取、写入和其他操作是原子的,这意味着在多线程环境下,对std::atomic类型的对象进行操作时不会发生数据竞争,从而避免了需要额外的锁来保护这些操作的情况。 -
提供内存顺序保证:
std::atomic也提供了内存顺序保证,确保所有线程都能够看到相同的操作顺序,从而避免了由于指令重排等导致的意外行为。 -
用于并发数据结构:
std::atomic在开发并发数据结构时非常有用,比如并发队列、栈、哈希表等,它可以确保在多线程环境下对这些数据结构的操作是线程安全的。最好还是用lock_guard搭配mutex来处理vector等STL容器。 -
提高性能:相比使用锁(如互斥锁)来进行同步,
std::atomic可能在某些情况下具有更好的性能,特别是对于一些简单的操作,因为它们不涉及线程的阻塞和唤醒。