原子写入和读取操作与加载/存储操作有何不同?我一直认为这是同一件事,但现在我有点困惑。
在查看了在标准原子上实现自旋锁的示例后,我感到困惑
struct tas_lock {
std::atomic<bool> lock_ = {false};
void lock() { while(lock_.exchange(true, std::memory_order_acquire)); }
void unlock() { lock_.store(false, std::memory_order_release); }
};
文件说,这就是混乱所在
memory_order_acquire 具有此内存顺序的加载操作对受影响的内存位置执行获取操作:在此加载之前,当前线程中的任何读取或写入都不能重新排序。释放相同原子变量的其他线程中的所有写入在当前线程中可见(请参阅下面的 Release-Acquire 顺序)
我的意思是,获取是一个加载操作(在我对阅读的理解中),它保证了原子性并且任何读写操作都不会在它之前重新排序。
memory_order_release 具有此内存顺序的存储操作执行释放操作:当前线程中的任何读取或写入都不能在此存储之后重新排序。当前线程中的所有写入在获取相同原子变量的其他线程中可见(请参阅下面的 Release-Acquire 排序),并且将依赖项携带到原子变量中的写入在消耗相同原子的其他线程中变得可见(请参阅 Release-Consume下面订购)。
一个解除分配操作,以确保没有读/写操作可以在它之后重新排序。
但是在上面的例子中,写操作是用asquire保证的(在我的理解中,交换是读+写)
while(lock_.exchange(true, std::memory_order_acquire));
鉴于上述情况,加载/释放和读/写的概念不是一回事,它们有何不同?
PS:描述 std::atomic_flag 的文档中的措辞也具有误导性
std::atomic_flag 是一个原子布尔类型。与 std::atomic 的所有特化不同,它保证是无锁的。与 std::atomic 不同,std::atomic_flag 不提供加载或存储操作。
这里写到 atomic_flag 不提供加载/存储操作,当使用 asq / release 保证的相同文档的示例中描述类似的自旋锁时,这不是很清楚这意味着什么
没什么,都是一样的。
.exchange()
不仅仅是写,它既是读又是写(“读-修改-写操作”)。他们可以使用任何顺序:至少,
release
至少acquire
,至少同时acq_rel
。它实际上没有任何方法
.load()
,并且.store()
取而代之的是更模糊的东西。C++20 添加了
.test()
,它本质上替换了.load()
,但.store()
不仅仅是.clear()
(类似于.store(false)
)和.test_and_set()
(类似于.exchange(true)
)。