c++ - 并发 std::call_once 调用

标签 c++ c++11

有人能解释一下为什么这个程序中的两个线程(当使用 Visual Studio 2012/2013 附带的编译器编译时)在两个 std::call_once 调用都被执行之前被阻塞吗?另一个 Visual Studio 错误(如果使用 GCC 编译时它的行为符合预期)?有人可以提出解决方法吗?想象一下我为缩小问题范围所经历的所有痛苦,请大发慈悲。

#include <chrono>
#include <iostream>
#include <mutex>
#include <thread>

namespace
{
    std::once_flag did_nothing;

    void do_nothing()
    { }

    void sleep_shorter_and_do_nothing_once()
    {
        std::this_thread::sleep_for(std::chrono::seconds(3));
        std::cout << "1\n";
        std::call_once(did_nothing, do_nothing);
        std::cout << "2\n";
    }

    std::once_flag sleeped_longer;

    void sleep_longer()
    {
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }

    void sleep_longer_once()
    {
        std::cout << "3\n";
        std::call_once(sleeped_longer, sleep_longer);
        std::cout << "4\n";
    }
}

int main()
{
    std::thread t1(sleep_shorter_and_do_nothing_once);
    std::thread t2(sleep_longer_once);
    t1.join();
    t2.join();
    return 0;
}

具体来说,使用 GCC 编译时它的行为符合预期:

  • 打印“3”,
  • 等待 3 秒,
  • 打印“1”,
  • 立即打印“2”,
  • 再等 6-7 秒,
  • 并打印“4”。

当使用 Visual Studio 2012/2013 附带的编译器编译时,它的行为如下:

  • 打印“3”,
  • 等待 3 秒,
  • 打印“1”,
  • 再等 6-7 秒
  • 然后才立即打印“2”和“4”

显然,这是一种不当行为。或者不是吗?

更新:我不能将此作为 Visual Studio 错误提交,因为我的工作帐户出于某种原因“无权提交此连接的反馈”,无论这意味着什么。我已收到 Microsoft STL 维护者的回复,称他希望在未来的某个时间调查此问题。

最佳答案

我收到了 Microsoft 的 STL 维护人员的回复,说该错误已在 Visual Studio 2015 中修复。

关于c++ - 并发 std::call_once 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26477070/

相关文章:

c++ 11子函数中的随机数生成器

c++ - asio::streambuf 优于原始数组的优势

c++ - 通过引用传递 char 数组

c++ - 类类型变量声明错误

Java 有垃圾收集,为什么 C 和 C++ 语言没有垃圾收集?

c++ - 两个不同的指针数组,但它们都指向同一个地址

c++ - 改变类型而不改变位

c++ - Windows GDI 上下文 - LoadImage 和 GetLastError()

c++ - std::regex 忽略正则表达式命令中的空格

c++ - 使用 OpenMP 和减少优化外循环