1
105
有读障碍和写障碍;获取障碍和释放障碍。更多(IO与内存等)。 这些障碍不存在于控制价值的“最新”价值或“新鲜度”上。它们用于控制内存访问的相对顺序。 写入屏障控制写入顺序。因为写入内存的速度很慢(与CPU的速度相比),所以通常会有一个写请求队列,在这个队列中,写操作会在“真正发生”之前发布。尽管它们是按顺序排队的,但是在队列中,写入操作可能被重新排序。(所以也许“队列”不是最好的名字…)除非你使用写屏障来防止重新排序。 读取屏障控制读取顺序。由于推测性的执行(CPU提前查看并提前从内存加载)和写缓冲区的存在(如果存在,CPU将从写缓冲区而不是内存中读取一个值-即CPU认为它刚刚写了x=5,那么为什么要读回它,只需看到它仍在等待 成为 写入缓冲区中的5)读取可能发生顺序错误。 不管编译器对生成代码的顺序做什么,这都是正确的。这里的“易失性”在C++中是无济于事的,因为它只告诉编译器输出代码以从“内存”重新读取值,它不告诉CPU如何/从哪里读取它(即“内存”是CPU级别的很多东西)。 因此,读/写屏障会设置块来防止读/写队列中的重新排序(读通常不太像队列,但重新排序效果相同)。 什么样的街区?-获取和/或释放块。 获取-例如,读取获取(X)会将X的读取添加到读取队列中。 冲洗队列 (不是真正刷新队列,而是添加一个标记,表示在此次读取之前不要对任何内容重新排序,这就好像刷新了队列一样)。所以以后(按代码顺序)的读取可以重新排序,但不能在X的读取之前。 释放-例如,写释放(x,5)将首先刷新(或标记)队列,然后将写请求添加到写队列。因此,较早的写入不会在x=5之后重新排序,但请注意,稍后的写入可以在x=5之前重新排序。 请注意,我将read与acquire和write与release配对,因为这是典型的,但可能有不同的组合。 获取和释放被认为是“半屏障”或“半围栏”,因为它们只会阻止重新排序单向进行。 一个完整的屏障(或完整的屏障)同时应用一个获得和一个释放-即没有重新排序。 通常用于无锁编程,或C或Java的“易失性”,您想要/需要的是 读取获取和写入释放。 工业工程
所以,首先,这是一个编程线程的坏方法。锁会更安全。但仅仅是为了说明障碍…
在threada()完成对foo的写入之后,它需要写入foo->ready last,really last,否则其他线程可能会看到foo->ready early,并获取错误的x/y/z值。因此,我们使用
现在,threadb()需要知道,当我们说“准备好”时,我们的意思是“准备好”。所以我们做了一个
还要注意,这通常是用于锁定和解锁互斥体/关键部分/etc的完全相同的屏障(即acquire on lock(),release on unlock())。 所以,
|
2
9
|
Bogey · C#共享内存-CPU缓存风险(非易失性读取)? 6 年前 |
filo · 如何在x86上使用gcc强制执行内存排序 7 年前 |
maxim1 · Java中的易失阵列、内存障碍和可见性 8 年前 |
paddy · 双原子自旋锁的最小限制存储器排序 8 年前 |