通常,缓存行是 64B,但非 volatile 内存的原子性是 8B。
例如:
x[1]=100;
x[2]=100;
clflush(x);
x
缓存行对齐,初始设置为 0
.系统崩溃
clflush();
可以吗x[1]=0
, x[2]=100
重启后?
最佳答案
在以下假设下:
存储的全局可观察性顺序可能与 Intel x86 处理器上的持久顺序不同。这称为松弛持久性。唯一保证顺序相同的情况是将 WB 类型的存储序列放入同一缓存行(但到达 GO 的存储并不一定意味着它变得持久)。这是因为
CLFLUSH
是原子的,WB 存储不能在全局可观察性中重新排序。见:On x86-64, is the “movnti” or "movntdq" instruction atomic when system crash? .如果两个存储跨越缓存线边界或者如果存储的有效内存类型是 WC:
x86-TSO 内存模型不允许重新排序存储,因此另一个代理不可能观察到
x[2] == 100
和 x[1] != 100
在正常操作期间(即在没有崩溃的 volatile 状态下)。但是,如果系统崩溃并重新启动,则持久状态可能为 x[2] == 100
和 x[1] != 100
.即使退休后系统崩溃,这也是可能的clflush
因为clflush
的退休并不一定意味着刷新的缓存行已到达持久域。如果你想消除它,你可以移动
clflush
如下:x[1]=100;
clflush(x);
x[2]=100;
clflush
英特尔处理器上的所有写入都是按顺序排列的,这意味着该行保证在任何后续存储变为全局可见之前到达持久域。见:Persistent Memory Programming Primary (PDF)和英特尔 SDM V2。第二家商店可以在同一行或任何其他行。如果你想要
x[1]=100
在之前变得持久 x[2]=100
成为全局可观察的,添加 sfence
之后 clflush
在英特尔 CSX 或 mfence
上在 AMD 处理器上(clflush
仅由 mfence
在 AMD 处理器上订购)。 clflush
本身足以控制持久顺序。或者,使用序列
clflushopt+sfence
(或 clwb+sfence
)如下:x[1]=100;
clflushopt(x);
sfence;
x[2]=100;
在这种情况下,如果发生崩溃并且如果 x[2] == 100
在持久状态下,则保证 x[1] == 100
. clflushopt
本身不会强加任何持久排序。
关于c - 系统崩溃时 clflush 或 clflushopt 是原子的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65439089/