提问人:cppguy 提问时间:11/16/2023 最后编辑:HolyBlackCatcppguy 更新时间:11/20/2023 访问量:63
静态初始化的哪一部分是线程安全的?
What part of static initialization is thread safe?
问:
如果我有一个这样的全局值获取器
bool get_global_bool() {
static const bool b{get_the_value()};
return b;
}
我知道这将以线程安全的方式初始化,但我是否也能保证并发调用的多个线程永远不会执行多次?b
get_global_bool
get_the_value
答:
1赞
kcbsbo
11/16/2023
#1
是的,它是根据 cppref
如果多个线程尝试初始化同一个静态本地 变量同时,初始化只发生一次(类似 可以使用 std::call_once) 获取任意函数的行为。
注意:此功能的通常实现使用双重检查锁定模式的变体,这减少了 已初始化为单个非原子布尔值的局部静态值 比较。
好吧,您也可以通过检查 gen asm 输出来验证它,输出类似于 x86-64 gcc trunk 上的以下内容
get_the_value():
movzx eax, BYTE PTR v[rip]
ret
get_global_bool():
movzx eax, BYTE PTR guard variable for get_global_bool()::b[rip]
test al, al
je .L14
movzx eax, BYTE PTR get_global_bool()::b[rip]
ret
.L14:
sub rsp, 8
mov edi, OFFSET FLAT:guard variable for get_global_bool()::b
call __cxa_guard_acquire
test eax, eax
jne .L15
movzx eax, BYTE PTR get_global_bool()::b[rip]
add rsp, 8
ret
.L15:
movzx eax, BYTE PTR v[rip]
mov edi, OFFSET FLAT:guard variable for get_global_bool()::b
mov BYTE PTR get_global_bool()::b[rip], al
call __cxa_guard_release
movzx eax, BYTE PTR get_global_bool()::b[rip]
add rsp, 8
ret
您可以看到get_the_value受 cxa_guard 保护,并且只调用一次
评论
0赞
James Kanze
11/21/2023
我很确定他们不会系统地使用双重检查锁定;它不适用于许多体系结构。在这种情况下,编译器可以看到它将工作,因为它已经内联了初始化函数,并且可以看到它没有对全局状态进行任何更改,但是根据初始化函数的内容,使用双重检查锁定,可能会出现特殊情况,即一个线程中的代码会看到初始化已经发生, 但会读取其他未发生的内存值。
0赞
James Kanze
11/21/2023
我在这里谈论的是反汇编代码中显示的低级双重检查锁定。可以使用 实现它,但要做到这一点,编译器必须生成一个围栏或一个 membar 或类似的东西。这在上面的汇编代码中不存在。atomic
评论