What exactly is std::atomic?
我知道
1 | a = a + 12; |
那么整个操作(比如
std::atomic<>的每个实例化和完全专用化表示一种类型,不同的线程可以同时操作(它们的实例),而不会引发未定义的行为:
Objects of atomic types are the only C++ objects that are free from data races; that is, if one thread writes to an atomic object while another thread reads from it, the behavior is well-defined.
In addition, accesses to atomic objects may establish inter-thread synchronization and order non-atomic memory accesses as specified by
std::memory_order .
另外,
- C++原子与内存排序
- 比较:在C++ 11中使用原子锁与互斥锁和RW锁的无锁编程
- C++ 11引入了标准化内存模型。这是什么意思?它会如何影响C++程序设计?
- C++ 11中的并发性
注意,对于典型的用例,您可能会使用重载的算术运算符或它们的另一组:
1 2 3 | std::atomic<long> value(0); value++; //This is an atomic op value += 5; //And so is this |
因为运算符语法不允许您指定内存顺序,所以这些操作将用EDCOX1 OR 8来执行,因为这是C++ 11中所有原子操作的默认顺序。它保证所有原子操作之间的顺序一致性(全局排序)。
然而,在某些情况下,这可能不是必需的(没有免费的东西),因此您可能希望使用更明确的形式:
1 2 3 | std::atomic<long> value {0}; value.fetch_add(1, std::memory_order_relaxed); // Atomic, but there are no synchronization or ordering constraints value.fetch_add(5, std::memory_order_release); // Atomic, performs 'release' operation |
现在,您的示例:
1 | a = a + 12; |
不会对单个原子操作进行评估:它将导致
但是,如果你写
关于你的评论:
A regular
int has atomic loads and stores. Whats the point of wrapping it withatomic<> ?
您的声明只适用于为存储和/或加载提供原子性保证的体系结构。有一些体系结构不能做到这一点。此外,通常要求必须在字/双字对齐地址上执行操作,使其成为原子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | void* sharedData = nullptr; std::atomic<int> ready_flag = 0; // Thread 1 void produce() { sharedData = generateData(); ready_flag.store(1, std::memory_order_release); } // Thread 2 void consume() { while (ready_flag.load(std::memory_order_acquire) == 0) { std::this_thread::yield(); } assert(sharedData != nullptr); // will never trigger processData(sharedData); } |
注意,断言条件将始终为真(因此永远不会触发),因此您可以始终确保,在
store() to the flag在sharedData 设置后执行(我们假设generateData() 总是返回有用的东西,特别是从不返回NULL 并使用std::memory_order_release 顺序:
memory_order_release A store operation with this memory order performs the release
operation: no reads or writes in the current thread can be reordered
after this store. All writes in the current thread are visible in
other threads that acquire the same atomic variable
sharedData 在while 循环退出后使用,因此在load() from标志返回非零值后使用。load() 使用std::memory_order_acquire 命令:
std::memory_order_acquire A load operation with this memory order performs the acquire operation
on the affected memory location: no reads or writes in the current
thread can be reordered before this load. All writes in other threads
that release the same atomic variable are visible in the current
thread.
这使您能够精确地控制同步,并允许您显式地指定代码可能/可能不会/将/不会的行为。如果只保证原子性本身,这是不可能的。尤其是当涉及到非常有趣的同步模型时,比如发行版消耗顺序。
I understand that
std::atomic<> makes an object atomic.
这是个观点问题…您不能将它应用于任意对象并使其操作成为原子的,但是可以使用为(大多数)整型和指针提供的特殊化。
a = a + 12;