有人能解释一下WRITE_ONCE和READ_ONCE的用法吗?WRITE_ONCE在内部使用volatile限定符,为什么?WRITE_ONCE和READ_ONCE如何解决缓存一致性问题?*(volatile __u8_alias_t *) p和(volatile __u8_alias_t *) *p的区别
WRITE_ONCE
READ_ONCE
*(volatile __u8_alias_t *) p
(volatile __u8_alias_t *) *p
4nkexdtk1#
它们本身并不做任何事情来解决并发性,但它们确实阻止了编译器做一些愚蠢的事情,比如从同一个内存位置加载一个值两次。这很重要,例如如果你正在访问HW,并且不想触发多个总线访问,可能会影响未来的读写。编译器会做这类事情,因为通常他们被允许优化对别名变量的访问,因为他们认为他们知道整个系统的行为。要真正支持并发,你需要考虑内存的一致性,以及当一个线程可以看到另一个值时,哪些值可以保证对另一个线程可见。(通过阅读较小部分的值并合并结果来避免“撕裂”)和指定内存屏障。内存屏障允许您确保由另一个字段保护的值在访问时对另一个线程可见。volatile单独读取或写入类似于C _Atomic使用memory_order_relaxed加载或存储,并且通常编译为相同的asm。请参阅何时将volatile与多线程一起使用?(从不,除非在Linux内核中)了解为什么这是正确的一些低级细节。在像ARMv 8这样具有加载-获取和存储-释放指令的ISA上,您更喜欢使用这些(通过smp_load_acquire/smp_store_release)而不是volatileREAD_ONCE和单独的屏障。大多数旧的ISA只有普通的加载和单独的屏障指令。内核的READ_ONCE/WRITE_ONCE模型就是围绕这一点设计的。
volatile
_Atomic
memory_order_relaxed
smp_load_acquire
smp_store_release
1条答案
按热度按时间4nkexdtk1#
它们本身并不做任何事情来解决并发性,但它们确实阻止了编译器做一些愚蠢的事情,比如从同一个内存位置加载一个值两次。这很重要,例如如果你正在访问HW,并且不想触发多个总线访问,可能会影响未来的读写。
编译器会做这类事情,因为通常他们被允许优化对别名变量的访问,因为他们认为他们知道整个系统的行为。
要真正支持并发,你需要考虑内存的一致性,以及当一个线程可以看到另一个值时,哪些值可以保证对另一个线程可见。(通过阅读较小部分的值并合并结果来避免“撕裂”)和指定内存屏障。内存屏障允许您确保由另一个字段保护的值在访问时对另一个线程可见。
volatile
单独读取或写入类似于C_Atomic
使用memory_order_relaxed
加载或存储,并且通常编译为相同的asm。请参阅何时将volatile与多线程一起使用?(从不,除非在Linux内核中)了解为什么这是正确的一些低级细节。在像ARMv 8这样具有加载-获取和存储-释放指令的ISA上,您更喜欢使用这些(通过
smp_load_acquire
/smp_store_release
)而不是volatile
READ_ONCE
和单独的屏障。大多数旧的ISA只有普通的加载和单独的屏障指令。内核的READ_ONCE
/WRITE_ONCE
模型就是围绕这一点设计的。