#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::async
和std::thread
,我必须忽略一些非常关键的要点。
答案 0 :(得分:1)
async
的结果是 future ,而不是正在运行的线程。 您必须通过说background.get()
来同步任务。没有它,客户端程序可能永远不会被执行。