gpt4 book ai didi

c++ - 解释双重检查锁定中的竞争条件

转载 作者:太空狗 更新时间:2023-10-29 19:46:40 27 4
gpt4 key购买 nike

void undefined_behaviour_with_double_checked_locking()
{
if(!resource_ptr) #1
{
std::lock_guard<std::mutex> lk(resource_mutex); #2
if(!resource_ptr) #3
{
resource_ptr.reset(new some_resource); #4
}
}
resource_ptr->do_something(); #5
}

if a thread sees the pointer written by another thread, it might not see the newly-created instance of some_resource, resulting in the call to do_something() operating on incorrect values. This is an example of the type of race condition defined as a data race by the C++ Standard, and thus specified as undefined behaviour.

问题> 我已经看到上面解释为什么代码有导致竞争条件的双重检查锁定问题。但是,我仍然很难理解问题出在哪里。也许一个具体的双线程分步工作流程可以帮助我真正理解上述代码的竞争问题。

书中提到的一种解决方案如下:

std::shared_ptr<some_resource> resource_ptr;
std::once_flag resource_flag;

void init_resource()
{
resource_ptr.reset(new some_resource);
}
void foo()
{
std::call_once(resource_flag,init_resource); #1
resource_ptr->do_something();
}
#1 This initialization is called exactly once

欢迎任何评论-谢谢

最佳答案

在这种情况下(取决于 .reset! 的实现)当线程 1 通过初始化 resource_ptr< 时可能会出现问题 然后暂停/切换。然后线程 2 出现,执行第一次检查,发现指针不为空,然后跳过锁/完全初始化检查。然后它使用部分初始化的对象(可能导致不好的事情发生)。然后线程 1 返回并完成初始化,但为时已晚。

部分初始化的 resource_ptr 之所以可能,是因为允许 CPU 对指令重新排序(只要它不改变单线程行为)。因此,虽然代码看起来应该完全初始化对象,然后将其分配给 resource_ptr,但优化后的汇编代码可能会做一些完全不同的事情,而且 CPU 也不能保证运行汇编按照它们在二进制文件中指定的顺序进行指令!

要点是,当涉及多个线程时,内存栅栏(锁)是保证事情按正确顺序发生的唯一方法。

关于c++ - 解释双重检查锁定中的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8570903/

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