mov 0x0ff, 10
sfence
mov 0x0ff, 12
sfence
它能在x86-CPU上执行吗:
mov 0x0ff, 12
sfence
?
mov 0x0ff, 10
sfence
mov 0x0ff, 12
sfence
它能在x86-CPU上执行吗:
mov 0x0ff, 12
sfence
?
是的,有些CPU可以按照您的建议执行。
即使您在其中加入了更强的围栏,例如mfence
或使用锁定指令,也不能保证第一次写入不会被优化掉。
总的来说,这是真实的:排序和围栏规则基本上告诉您哪些执行是不允许的,因此保证永远不会出现,但是考虑到允许发生的补充执行集合,则通常没有保证任何特定的执行可能实际上被观察到。
尽管如此,在当前的x86芯片上,我非常确定您始终能够观察到偶尔出现的10值(即使完全省略了围栏),因为您可以偶尔在两个存储之间获得中断,从而允许您读取10。
然而,这并不是保证-人们当然可以想象像Denver或Transmeta这样的动态优化x86架构可以压缩上述序列,删除两个围栏和第一个存储,使20成为唯一可观察的值。
mfence
不会导致上下文切换,我不认为我暗示过这一点。我的意思是即使使用“更重”的fence,也不能保证在所有过去、现在和未来的x86芯片上都观察到10。当然,如果mfence
需要很多周期,可能在mfence
指令附近发生上下文切换的可能性更大,但我的回答并不依赖于此,我也不完全理解你讨论的这种影响。 - BeeOnRopesfence
是多余的,但如果在此段之前/之后有NT存储,则可能会产生影响,因此它们通常可以被删除,但并非总是如此。另请参见此评论。 - BeeOnRope
sfence
指令是多余的(相关:Does SFENCE prevent the Store Buffer hiding changes from MESI?)。但即使没有它们,我认为另一个线程有时也可能观察到10
。不过,在存储器队列提交到 L1D 之前,存在一些合并的证据,尽管我找不到关于此的 SO 答案或评论。 - Peter Cordes10
可能永远不会提交到L1d。我不知道sfence
是否可以防止这种情况,我认为在理论上它不必这样做,但它可能会阻止实际CPU上的合并。 - Peter Cordessfence
会清空存储缓冲区(根据英特尔的说法),因此它应该可以防止合并。它对于排序来说是多余的,但我认为对于可见性来说不是这样。 - Margaret Bloomsfence
作为排空存储缓冲区,但我觉得很难相信(至少在同步排空存储缓冲区之前),因为它似乎意味着sfence; lfence
将等同于 mfence,但英特尔明确表示它不是,并且执行速度更快,因此从实际角度来看,我认为它不是等效的。我觉得这种语言是早期留下的,不能依赖它,尽管我承认我对此不太清楚。 - BeeOnRope