std::memory_order 在 C++ 中究竟提供了哪些围栏?
Which fences exactly provided by std::memory_order in C++?
据我所知,std::memory_order 枚举提供内存栅栏,但我需要确定每个 std::memory_order 枚举元素提供的栅栏。
下面我解释一下我对每个 std::memory_order 枚举元素的理解:
- std::memory_order_relaxed - 没有提供围栏
- std::memory_order_获取 - LoadLoad_LoadStore
- std::memory_order_release - LoadStore_StoreStore
- std::memory_order_consume - 通常等于 memory_order_acquire
- std::memory_order_acq_rel - LoadLoadLoadStore_LoadStoreStoreStore ???
- std::memory_order_seq_cst - StoreLoad_StoreLoad ???
关于前 4 个元素,我不确定。
但是关于最后两个元素,我什么都不知道。
有人知道吗?
此外,我需要知道编译器在使用 std::atomic 或 std::atomic_flag 时将内存栅栏放在哪个位置?
据我了解,使用带有原子的栅栏意味着应用栅栏并执行操作。我对吗?
例如:
atomic.load(std::memory_order_acquire);
表示应用 memory_order_acquire 以原子方式隔离和加载数据?
Anyone exactly knows about that?
当然,有多种来源,例如C++ Reference:
memory_order_relaxed — 宽松的操作:没有同步或顺序约束强加于其他读取或写入,只保证此操作的原子性。
memory_order_consume — 具有此内存顺序的加载操作对受影响的内存位置执行消耗操作:当前线程中没有读取或写入取决于该值当前加载的可以在此加载之前重新排序。在释放相同原子变量的其他线程中写入数据相关变量在当前线程中是可见的。在大多数平台上,这只会影响编译器优化。
memory_order_acquire — 具有此内存顺序的加载操作在受影响的内存位置执行获取操作:之前不能对当前线程中的读取或写入进行重新排序这个负载。在其他线程中释放同一个原子变量的所有写入在当前线程中都是可见的。
memory_order_release — 具有此内存顺序的存储操作执行释放操作:在此存储之后,当前线程中的读取或写入不能重新排序。当前线程中的所有写入在获取相同原子变量的其他线程中可见,并且对原子变量进行依赖的写入在使用相同原子的其他线程中变得可见。
memory_order_acq_rel — 这种内存顺序的读取-修改-写入操作既是获取操作又是释放操作。当前线程中的内存读取或写入不能在此存储之前或之后重新排序。所有在其他线程中释放同一个原子变量的写入在修改前可见,并且修改在其他获取相同原子变量的线程中可见。
memory_order_seq_cst — 这种内存顺序的加载操作执行获取操作,存储执行释放操作,读取-修改-写入执行获取操作操作和释放操作,再加上存在一个单一的总顺序,其中所有线程以相同的顺序观察所有修改。
也请看一下atomic<> Weapons presentation by Herb Sutter,里面解释了很多。
Also, I need know in which place compiler puts memory fence
这取决于体系结构。在一些架构上它是一个空操作,在一些它是一个指令前缀,在一些它会是一个特殊的指令 before/after load/store.
有一篇论文叫"Memory Barriers: a Hardware View for Software Hackers",如果你感兴趣的话,它分析了很多架构上的障碍。
For example: atomic.load(std::memory_order_acquire);
means apply memory_order_acquire fence and load data atomically?
这也是依赖于体系结构的,但是对于获取障碍,我会说完全相反:我们加载一个变量,然后我们确保在加载之前没有进一步的 reads/writes,即放置一个栅栏。
但在某些平台上,它可能是单处理器指令。例如在 ARM 上有加载获取 (LDA) 和存储释放 (STL) 指令。
据我所知,std::memory_order 枚举提供内存栅栏,但我需要确定每个 std::memory_order 枚举元素提供的栅栏。 下面我解释一下我对每个 std::memory_order 枚举元素的理解:
- std::memory_order_relaxed - 没有提供围栏
- std::memory_order_获取 - LoadLoad_LoadStore
- std::memory_order_release - LoadStore_StoreStore
- std::memory_order_consume - 通常等于 memory_order_acquire
- std::memory_order_acq_rel - LoadLoadLoadStore_LoadStoreStoreStore ???
- std::memory_order_seq_cst - StoreLoad_StoreLoad ???
关于前 4 个元素,我不确定。 但是关于最后两个元素,我什么都不知道。
有人知道吗?
此外,我需要知道编译器在使用 std::atomic 或 std::atomic_flag 时将内存栅栏放在哪个位置?
据我了解,使用带有原子的栅栏意味着应用栅栏并执行操作。我对吗? 例如:
atomic.load(std::memory_order_acquire);
表示应用 memory_order_acquire 以原子方式隔离和加载数据?
Anyone exactly knows about that?
当然,有多种来源,例如C++ Reference:
memory_order_relaxed — 宽松的操作:没有同步或顺序约束强加于其他读取或写入,只保证此操作的原子性。
memory_order_consume — 具有此内存顺序的加载操作对受影响的内存位置执行消耗操作:当前线程中没有读取或写入取决于该值当前加载的可以在此加载之前重新排序。在释放相同原子变量的其他线程中写入数据相关变量在当前线程中是可见的。在大多数平台上,这只会影响编译器优化。
memory_order_acquire — 具有此内存顺序的加载操作在受影响的内存位置执行获取操作:之前不能对当前线程中的读取或写入进行重新排序这个负载。在其他线程中释放同一个原子变量的所有写入在当前线程中都是可见的。
memory_order_release — 具有此内存顺序的存储操作执行释放操作:在此存储之后,当前线程中的读取或写入不能重新排序。当前线程中的所有写入在获取相同原子变量的其他线程中可见,并且对原子变量进行依赖的写入在使用相同原子的其他线程中变得可见。
memory_order_acq_rel — 这种内存顺序的读取-修改-写入操作既是获取操作又是释放操作。当前线程中的内存读取或写入不能在此存储之前或之后重新排序。所有在其他线程中释放同一个原子变量的写入在修改前可见,并且修改在其他获取相同原子变量的线程中可见。
memory_order_seq_cst — 这种内存顺序的加载操作执行获取操作,存储执行释放操作,读取-修改-写入执行获取操作操作和释放操作,再加上存在一个单一的总顺序,其中所有线程以相同的顺序观察所有修改。
也请看一下atomic<> Weapons presentation by Herb Sutter,里面解释了很多。
Also, I need know in which place compiler puts memory fence
这取决于体系结构。在一些架构上它是一个空操作,在一些它是一个指令前缀,在一些它会是一个特殊的指令 before/after load/store.
有一篇论文叫"Memory Barriers: a Hardware View for Software Hackers",如果你感兴趣的话,它分析了很多架构上的障碍。
For example:
atomic.load(std::memory_order_acquire);
means apply memory_order_acquire fence and load data atomically?
这也是依赖于体系结构的,但是对于获取障碍,我会说完全相反:我们加载一个变量,然后我们确保在加载之前没有进一步的 reads/writes,即放置一个栅栏。
但在某些平台上,它可能是单处理器指令。例如在 ARM 上有加载获取 (LDA) 和存储释放 (STL) 指令。