#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::async
and的非常关键的点std::thread
。