原子地修改两个变量的惯用方法是使用锁。
std::unique_ptr
没有锁你不能这样做。Evenstd::atomic<int>
没有提供一种原子交换两个值的方法。您可以自动更新一个并取回其先前的值,但从概念上讲,交换是三个步骤,就std::atomic
API 而言,它们是:
auto tmp = a.load();
tmp = b.exchange(tmp);
a.store(tmp);
这是一个 atomic read后跟 atomic read-modify-write后跟 atomic write。每个步骤都可以原子地完成,但你不能在没有锁的情况下原子地完成这三个步骤。
对于不可复制的值,例如std::unique_ptr<T>
您甚至不能使用上面的load
andstore
操作,但必须这样做:
auto tmp = a.exchange(nullptr);
tmp = b.exchange(tmp);
a.exchange(tmp);
这是三个读-修改-写操作。(你不能真的std::atomic<std::unique_ptr<T>>
这样做,因为它需要一个可简单复制的参数类型,并且std::unique_ptr<T>
不是任何可复制的。)
要使用更少的操作来做到这一点,需要一个不支持的不同 API,std::atomic
因为它无法实现,因为正如 Stas 的回答所说,大多数处理器都不可能。C++ 标准没有将功能标准化的习惯,这在所有当代架构上都是不可能的。(反正不是故意的!)
编辑:您更新的问题询问了一个非常不同的问题,在第二个示例中,您不需要影响两个对象的原子交换。只有global
在线程之间共享,所以你不关心更新是否local
是原子的,你只需要原子地更新global
和检索旧值。规范的 C++11 方法是使用std:atomic<T*>
并且您甚至不需要第二个变量:
atomic<T*> global;
void f() {
delete global.exchange(new T(...));
}
这是一个单一的读-修改-写操作。