【问题标题】:std::async from std::async in windows xpWindows XP 中来自 std::async 的 std::async
【发布时间】:2019-03-15 02:53:15
【问题描述】:

此示例在 windows7 和 ideone.com 上打印所有 2 条消息,但无法在 windows xp 上打印第二条消息。我做错了什么?如果是错误,我应该在哪里报告?

使用 Visual Studio 2017 为 windows xp 编译,平台工具集 v141_xp。

#include <iostream>
#include <future>
#include <thread>

using namespace std;
int main()
{
    auto f1 = async(launch::async, []()->int {
        cout << "in outer async" << endl;

         auto f2 = async(launch::async, []()->int {
             cout << "in inner async" << endl;
             return 2;
         });
         f2.get();

        return 1;
    });
    f1.get();

    return 0;
}

使用 std::thread 而不是 std::async 进行内部函数时的 UPD - 它在两个系统上都运行良好

auto f2 = thread([]()->int {
    cout << "in inner async" << endl;
    return 2;
});
f2.join();

UPD2

visual studio 2017 cl.exe 版本 19.14.26428 工具集 v141_xp

命令行:

/permissive- /Yu"stdafx.h" /GS /GL /analyze- /Wall /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"Release\vc141.pdb" /Zc:inline /fp:precise /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_USING_V110_SDK71_" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /std:c++17 /FC /Fa"Release\" /EHsc /nologo /Fo"Release\" /Fp"Release\testasync.pch" /diagnostics:classic 

在 windows xp 上使用时,UPD3 看起来像 launch::async 被忽略

vector<future<void>> v;
for( int i = 0; i < 10; i++ )
    v.push_back(async(launch::async, []() {cout << "thread" << endl; this_thread::sleep_for(5s); }));
for( auto &f : v )
    f.get();

在 windows7 上这需要大约 6 秒才能完成,在 windows xp 上大约需要 50 秒

【问题讨论】:

  • 编译器版本?编译器命令?
  • 那么会发生什么?行 cout &lt;&lt; "in inner async" &lt;&lt; endl; 是否已执行但在输出中不可见还是什么?
  • stackoverflow.com/q/6374264/4955498 但这并不能解释缺少文本,只能解释混合文本。此外,第二个 cout 仅在第一个 cout 完成后发生,因此在这种情况下不适用混合
  • @Fl0 你应该发布正确的问题描述。 “无法打印第二条消息”和“程序只是挂起”是完全不同的。它挂在哪一行?最好也包含用于运行线程的调用堆栈。
  • 在 windows XP 上你的程序完成了吗?在 Windows 中,std::async(...) 位于线程池之上。所以可能会出现死锁。在f1 中运行新任务并调用f2.get(),它会阻塞直到f2 完成。但是如果auto f2 = async(...) 选择了运行f1 的同一个线程,那么你就会出现死锁并且你的程序不应该完成。如果是这样,那么情况并非如此。

标签: c++ visual-c++ windows-xp


【解决方案1】:

在 Windows 上,std::async(...) 位于线程池之上。所以可能会出现死锁。在f1 中运行新任务并调用f2.get(),这会阻塞直到f2 完成。但是如果auto f2 = async(...) 选择了运行f1 的同一个线程,那么你就会出现死锁并且你的程序不应该完成。如果是,那么情况并非如此。

更新

请阅读有关 std::async here 的 Microsoft 实现。 它说:

C++ 标准规定,如果策略是 launch::async,则函数会创建一个新线程。但是,Microsoft 实施目前不符合要求。它从 Windows ThreadPool 中获取其线程,在某些情况下,它可能会提供一个回收的线程而不是一个新的线程。这意味着launch::async策略实际上是作为launch::async|launch::deferred实现的

还有一个answer,它揭示了微软std::async实现的一个特殊功能:

  • 它限制了它使用的后台线程总数,之后对 std::async 的调用将阻塞,直到线程空闲。在我的机器上,这个数字是 768。

所以,我假设,如果您在 ThreadPool 中只有一个线程,那么从任务内部对 std::async 的调用将死锁。考虑到您的 UPD3,可能是您的情况。

我真的推荐阅读上面提到的answer,这样你就可以理解为什么微软的std::async不一样,以及如何正确使用它。

【讨论】:

  • 将内部异步更改为 f2 = thread( lambda ); f2.join();做这项工作。 std::thread 的行为是否与 std::async 不同?
  • When the same thread in which f1 runs is selected call to f2.get() will never lead to a deadlock, rather it will be executed synchronously.如果您的逻辑从其他异步任务内部的异步任务中创建和获取值,则会导致随机死锁,从而使异步完全无法使用......
  • 不确定我是否遵循这个。如果两个回调在同一个线程上运行,它们之间怎么可能出现死锁?
  • @nicolai 如果是这样,那将是一个非常愚蠢的实现。如果f2 发往同一个线程,f2.get() 应该简单地调用回调而不阻塞。当 async 决定不使用工作线程时,它就是这样工作的。为什么它会阻塞等待它想在自己的线程上做的事情?傻!
  • @nicolai 链接文档的哪一部分涵盖了这个案例? asynclaunch::async 需要表现得好像已经产生了一个新线程,并且当调用 f2.get() 时,执行 f1 的线程准备好执行 f2。无论实现是使用线程池、生成新线程还是在主线程中运行所有内容,这都应该有效。
猜你喜欢
  • 2012-04-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
  • 1970-01-01
  • 1970-01-01
  • 2018-11-26
  • 2012-07-13
  • 2021-11-24
相关资源
最近更新 更多