使用CALL_ONCE与Atomic_flag的多线程程序初始化

发布于 2025-02-13 18:47:03 字数 1022 浏览 0 评论 0 原文

在《行动2》中的书籍 c ++并发中,作者引入了一种使用 call_once 函数的方式

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]中解释了原因。我曾经使用 atomic_flag 在多线程程序中进行初始化,诸如此类:

td::atomic_flag init = ATOMIC_FLAG_INIT;
std::atomic<bool> initialized = false;
void Init()
{
if (init.test_and_set()) return;
  DoInit();
  initialized = true;
}
void Foo(){
  if(!initialized) return;
   DoSomething(); // use some variable intialized in DoInit()
}

每个线程都会调用 init() >。

阅读本书后,我想知道上述模式会导致种族状况,因此使用不安全?编译器是否有可能在 doinit()完成之前重新排序指令和初始化? [1]:在双重检查的锁定中解释种族条件

In book C++ Concurrency in Action 2nd, 3.3.1, the author introduced a way using call_once function to avoid double-checked locking pattern when doing initialization in multi-thread program,

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();
}

the reason is explained in this [answer][1]. I used to use atomic_flag to do initialization in multi-thread program, something like this:

td::atomic_flag init = ATOMIC_FLAG_INIT;
std::atomic<bool> initialized = false;
void Init()
{
if (init.test_and_set()) return;
  DoInit();
  initialized = true;
}
void Foo(){
  if(!initialized) return;
   DoSomething(); // use some variable intialized in DoInit()
}

every threads will call Init() before call Foo().

After read the book, I wonder will the above pattern cause race condition, therefore not safe to use? Is it possible that the compiler reorder the instructions and initialized become true before DoInit() finish?
[1]: Explain race condition in double checked locking

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

无名指的心愿 2025-02-20 18:47:03

当线程1输入 doInit 和Thread 2跳过并继续进行 foo 时,代码中的竞赛条件会发生。

您使用进行处理,如果(!初始化)返回 in foo ,但这并非总是可能的:您应该始终期望一种方法不小心做任何事情,您可能会忘记添加这样的方法检查其他方法。

使用 std :: Call_once 并并发调用,只有在执行操作后,执行才会继续。

关于重新排序,Atomics操作使用 nofollow noreferrer'> remote_order_serd_seq_cst 默认情况下,允许任何重新排序。

The race condition in your code happens when thread 1 enters DoInit and thread 2 skips it and proceeds to Foo.

You handle it with if(!initialized) return in Foo but this is not always possible: you should always expect a method to accidently do nothing and you can forget to add such checks to other methods.

With std::call_once with concurrent invocation the execution will only continue after the action is executed.

Regarding reordering, atomics operations use memory_order_seq_cst by default that does not allow any reordering.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文