gpt4 book ai didi

c++11 - x86 mfence 和 C++ 内存屏障

转载 作者:行者123 更新时间:2023-12-02 23:24:11 27 4
gpt4 key购买 nike

我正在检查编译器如何在 x86_64 上发出多核内存屏障指令。以下代码是我使用 gcc_x86_64_8.3 测试的代码。

std::atomic<bool> flag {false};
int any_value {0};

void set()
{
any_value = 10;
flag.store(true, std::memory_order_release);
}

void get()
{
while (!flag.load(std::memory_order_acquire));
assert(any_value == 10);
}

int main()
{
std::thread a {set};
get();
a.join();
}

当我使用std::memory_order_seq_cst时,我可以看到MFENCE指令与任何优化-O1、-O2、-O3一起使用>。该指令确保存储缓冲区被刷新,从而更新 L1D 缓存中的数据(并使用 MESI 协议(protocol)确保其他线程可以看到效果)。

但是,当我使用没有优化的 std::memory_order_release/acquire 时,也会使用 MFENCE 指令,但使用 -O1、-O2 省略该指令, -O3 优化,并且没有看到其他刷新缓冲区的指令。

在不使用MFENCE的情况下,如何确保存储缓冲区数据提交到缓存内存以确保内存顺序语义?

下面是带有 -O3 的 get/set 函数的汇编代码,就像我们得到的 on the Godbolt compiler explorer :

set():
mov DWORD PTR any_value[rip], 10
mov BYTE PTR flag[rip], 1
ret


.LC0:
.string "/tmp/compiler-explorer-compiler119218-62-hw8j86.n2ft/example.cpp"
.LC1:
.string "any_value == 10"

get():
.L8:
movzx eax, BYTE PTR flag[rip]
test al, al
je .L8
cmp DWORD PTR any_value[rip], 10
jne .L15
ret
.L15:
push rax
mov ecx, OFFSET FLAT:get()::__PRETTY_FUNCTION__
mov edx, 17
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:.LC1
call __assert_fail

最佳答案

x86 内存排序模型为所有存储指令提供#StoreStore 和#LoadStore 屏障1,这正是释放语义所需要的。处理器也会尽快提交存储指令;当存储指令退出时,存储成为存储缓冲区中最旧的,核心使目标缓存线处于可写一致性状态,并且缓存端口可用于执行存储操作2。因此不需要 MFENCE 指令。该标志将尽快对其他线程可见,并且当它出现时,any_value 保证为 10。

另一方面,顺序一致性也需要#StoreLoad 和#LoadLoad 屏障。 MFENCE 需要同时提供3 个屏障,因此它可用于所有优化级别。

相关:Size of store buffers on Intel hardware? What exactly is a store buffer? .

<小时/>

脚注:

(1) 有些异常(exception)情况在此不适用。特别是,非临时存储和不可缓存写入组合内存类型的存储仅提供#LoadStore 屏障。无论如何,这些屏障是为 Intel 和 AMD 处理器上的回写内存类型的存储而提供的。

(2) 这与在某些条件下全局可见的写入组合存储形成对比。请参阅英特尔手册第 3 卷第 11.3.1 节。

(3) 请参阅 Peter 的回答下的讨论。

关于c++11 - x86 mfence 和 C++ 内存屏障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55231677/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com