c++ - std::call_once 是阻塞调用吗?

标签 c++ multithreading c++11 c++-standard-library

我在我的代码中使用 std::call_once 只初始化一些共享变量一次。调用代码位于由多个线程触发的回调中。 我有兴趣知道,因为我在文档中找不到它,所以 std::call_once 是否本质上是阻塞的,就好像有一个 std::lock_guard反而? 在实践中看起来是这样的。

例如,以下将在调用任何 print() 之前打印 "Done":

#include <future>
#include <iostream>
#include <thread>
#include <mutex>

std::once_flag flag;

void print()
{
    for(int i=0;i<10;i++)
    {
          std::cout << "Hi, my name is " << std::this_thread::get_id() 
            << ", what?" << std::endl;
    }
}

void do_once()
{
    std::cout << "sleeping for a while..." << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    std::cout << "Done" << std::endl;
}

void work()
{
    std::call_once(flag, [](){ do_once(); });
    print();
}


int main()
{
    auto handle1 = std::async(std::launch::async, work);
    auto handle2 = std::async(std::launch::async, work);
    auto handle3 = std::async(std::launch::async, work);
    auto handle4 = std::async(std::launch::async, work);

    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}

我假设这确实是这种情况(因为我不知道如何以其他方式实现它),但是这种行为是否得到保证,或者是否可以有一个编译器决定 std::call_once 确实会被调用一次但允许其他线程继续并忽略此调用?

最佳答案

std::call_once是一个阻塞调用。从 [thread.once.callonce] 我们有

Effects: An execution of call_once that does not call its func is a passive execution. An execution of call_once that calls its func is an active execution. An active execution shall call INVOKE (DECAY_COPY ( std::forward<Callable>(func)), DECAY_COPY (std::forward<Args>(args))...). If such a call to func throws an exception the execution is exceptional, otherwise it is returning. An exceptional execution shall propagate the exception to the caller of call_once. Among all executions of call_once for any given once_flag: at most one shall be a returning execution; if there is a returning execution, it shall be the last active execution; and there are passive executions only if there is a returning execution. [ Note: passive executions allow other threads to reliably observe the results produced by the earlier returning execution. —end note ]

Synchronization: For any given once_flag: all active executions occur in a total order; completion of an active execution synchronizes with (1.10) the start of the next one in this total order; and the returning execution synchronizes with the return from all passive executions.

强调我的

这意味着所有对 call_once 的调用将等到函数传递给 call_once完成。在您的情况下,这意味着 do_once()必须在任何线程调用之前调用 print()

关于c++ - std::call_once 是阻塞调用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43054677/

相关文章:

c++ - 使用 C++ 特化模板时的奇怪行为

c++ - 使用包在 Raspberry Pi 上安装 OpenCV

c++ - 字符串比较很奇怪

c# - 全局类实例计数(使用信号量)

C++ Auto 关键字 - Float 与 Int 问题

c++ - C++ 17的新功能是什么?

c - 使用多线程读取文件

c# - 关闭在 Windows 服务中等待计时器的线程

c++ - 操作原始内存的正确数据类型

c++ - 是否可以从 c++ 类模拟私有(private)/ protected 方法而不从它继承?