std :: call_once是阻塞调用吗?

时间:2017-03-27 19:17:19

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

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

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

#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一次,但允许其他线程继续,只是忽略这个电话?

1 个答案:

答案 0 :(得分:4)

std::call_once是阻止来电。从[thread.once.callonce]我们有

  

效果:执行不调用其func的call_once是被动执行。调用其func的call_once的执行是一个活动执行。主动执行应调用INVOKE (DECAY_COPY ( std::forward<Callable>(func)), DECAY_COPY (std::forward<Args>(args))...)。如果对func的这种调用抛出异常,则执行异常,否则返回。异常执行应将异常传播给call_once的调用者。在任何给定call_once的{​​{1}}的所有执行中:最多只执行一次;如果有回归   执行,它应该是最后一次执行;只有在返回执行时才会执行被动执行。 [注意:被动执行允许其他线程可靠地观察先前返回执行产生的结果。 - 后注]

     

同步:对于任何给定的once_flag:所有活动执行都按总顺序发生;活动执行的完成与(1.10)该总订单中下一个的开始同步; 并且返回的执行与所有被动执行的返回同步。

强调我的

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

之前调用do_once()