std::x86 上需要memory_order_acquire围栏吗?
std::memory_order_acquire fence necessary on x86?
鉴于 x86 具有强大的内存模型,是否需要std::memory_order_acquire
围栏(非操作(?
例如,如果我有以下代码:
uint32_t read_shm(const uint64_t offset) {
// m_head_memory_location is char* pointing to the beginning of a mmap-ed named shared memory segment
// a different process on different core will write to it.
return *(uint32_t*)(m_head_memory_location + offset);
}
....
int main() {
uint32_t val = 0;
while (0 != (val = shm.read(some location)));
.... // use val
}
在返回声明之前我真的需要std::atomic_thread_fence(std::memory_order_acquire)
吗?
我觉得没有必要,因为上面代码的目标是尝试从m_head_memory_location + offset
中读取前 4 个字节,因此重新排序围栏后的任何内存操作都不会影响结果。
还是有一些副作用使得需要获取围栏?
在x86 上是否需要采集围栏(而不是操作(?
欢迎任何意见。
return *(uint32_t*)(m_head_memory_location + offset);
您投射到非atomic
非volatile
uint32_t*
和取消引用!!
编译器可以假设这个uint32_t
对象不是由其他任何东西编写的(即假设没有数据竞争 UB(,因此它可以并且会将负载提升到循环之外,有效地将其转换为类似if((val=load) == 0) infinite_loop();
的东西。
- https://electronics.stackexchange.com/questions/387181/mcu-programming-c-o2-optimization-breaks-while-loop/387478#387478
- 多线程程序卡在优化模式下,但在 -O0 中正常运行
- 何时将易失性与多线程一起使用?(永远不要将原子与mo_relaxed一起使用(
GCC 内存屏障将强制重新加载,但这是std::atomic_thread_fence(std::memory_order_acquire)
的实现细节。 对于 x86,该屏障只需要阻止编译时重新排序,因此 GCC 的典型实现可能是asm("" ::: "memory")
。
不是获取顺序在做任何事情,而是阻止 GCC 假设另一个读取将读取相同内容的内存破坏者。 这不是ISO C++std::atomic_thread_fence(std::memory_order_acquire)
对非原子变量所暗示的。 (它总是暗示原子和易失性(。 所以就像我说的,这将在GCC中工作,但只能作为实现细节。
如果此内存使用char*
以外的其他类型访问,或者如果底层内存被声明为char[]
数组,它也是严格混叠 UB。 如果你从mmap
或其他东西那里得到了char*
,那么你就没事了。
也可能是UB错位,除非已知offset
是4的倍数。 (尽管除非 GCC 选择自动矢量化,否则这在 x86 上不会在实践中咬你。
你可以用typedef uint32_t unaligned_u32 __attribute((may_alias, aligned(1)));
解决GNU C的这两个问题,但你仍然需要volatile
或atomic<T>
才能循环读取才能工作。
通常
根据C++内存模型的要求使用std::atomic_thread_fence(std::memory_order_acquire);
;这就是在编译时控制重新排序的原因。
当编译x86时,它不会变成任何asm指令;在asm中,它是一个无操作。 但是,如果您不告诉编译器它无法对某些内容进行重新排序,则代码可能会中断,具体取决于编译器优化级别。
您可能会很幸运,让编译器在原子mo_relaxed
加载后执行非原子加载,或者如果您不告诉它不要这样做,它可能会更早地执行非原子加载。
- Ascending order c++
- 如何处理Boost Spirit X3导致Visual Studio 2019 "static initialization order fiasco"?
- 为什么'acquire/release'不能保证 c++11 中的顺序一致性?
- "static initialization order fiasco"是 constexpr 变量的问题吗?
- 在使用 In Order 遍历成员函数时引发异常(堆栈溢出)时出现问题
- 为什么在与静态库链接时强制执行 order(例如 source.cxx -lstatic)
- "The order of evaluation of expressions is left to right."是什么意思
- memory_order_seq_cst操作的"happens before"关系和"precedes in a single total order"关系有什么区别?
- std::shared_ptr::owner_before 和 std::owner_less:"owner-based order"到底是什么意思?
- C++: The order of std::cout
- "acquire" 和"consume"内存顺序有何不同,何时"consume"可取?
- 如何在 std::set 中为 FIND 和 ORDER 定义不同的条件
- 错误:arma::memory::acquire():犰狳的内存不足
- C++ 在结构上实现 ORDER BY
- Xcode-在项目导航器中创建新的C++文件-Order.h和.cpp-Order
- Order of cvScalar
- Xcode C++ Struct Order
- 使用c++编写带有BOM (Byte Order Mark)的csv文件
- 如果一个线程在临界区上调用Acquire(),如果另一个线程调用Release(),该锁会被释放吗?
- 为什么TMutex方法Acquire()不锁定互斥对象?