访问异步任务中的可调用对象与使用std :: cin冲突

时间:2013-05-28 08:02:01

标签: asynchronous c++11 task cin std-function

#include <iostream>
#include <functional>
#include <future>
#include <tchar.h>

void StartBackground(std::function<void()> notify)
{
    auto background = std::async([&]
    {
        notify(); // (A)
    });
}

int _tmain(int argc, _TCHAR* argv[])
{
    StartBackground([](){});

    char c; std::cin >> c;  // (B)
    while (1);
    return 0;
}

1)使用Visual Studio 2012构建并运行上面的代码。

2)行(A)在_VARIADIC_EXPAND_P1_0(_CLASS_FUNC_CLASS_0, , , , )

中触发访问冲突
  

0x0F96271E(msvcp110d.dll)中的第一次机会异常   ConsoleApplication1.exe:0xC0000005:访问冲突写入位置   0x0F9626D8

最令人困惑的是,删除行(B)可以避免异常。

问题

  • 为什么可调用对象notify显然与使用std::cin冲突?
  • 这段代码出了什么问题?

此简化示例的真实场景是一个并行执行某些代码的函数,并且该代码在完成后会调用用户提供的通知函数。

修改

我的代码中至少发现了一个问题:background变量会在StartBackground()退出后立即销毁。由于std::async可能会也可能不会启动单独的线程,如果线程仍可加入,则std::thread会调用terminate(),这可能会导致问题。 以下变体有效,因为它为任务提供了足够的时间来完成:

void StartBackground(std::function<void()> notify)
{
    auto background = std::async([&]
    {
        notify(); // (A)
    });

    std::this_thread::sleep_for(std::chrono::seconds(1));
}

保持std::future对象在较长时间内保持活着而不是睡觉也应该有效。但是以下代码也会导致相同的访问冲突:

std::future<void> background;

void StartBackground(std::function<void()> notify)
{
    background = std::async([&]
    {
        notify(); // (A)
    });
}

而以相同方式使用std::thread按预期工作:

std::thread background;

void StartBackground(std::function<void()> notify)
{
    background = std::thread([&]
    {
        notify(); // (A)
    });
}

我完全不解。 关于std::asyncstd::thread,我必须忽略一些非常关键的要点。

1 个答案:

答案 0 :(得分:1)

async的结果是 future ,而不是正在运行的线程。 必须通过说background.get()来同步任务。没有它,客户端程序可能永远不会被执行。