0
#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, , , , )

ConsoleApplication1.exe 中 0x0F96271E (msvcp110d.dll) 的第一次机会异常: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相同的方式使用 a 按预期工作:

std::thread background;

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

我完全不解。我必须在这里遗漏一些关于std::asyncand的非常关键的点std::thread

4

1 回答 1

1

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

于 2013-05-28T08:40:59.947 回答