在C++11中,触发异步任务并忘记它的方法是什么?

ni65a41a  于 2023-03-05  发布在  其他
关注(0)|答案(2)|浏览(112)

我需要这样的东西:

void launch_task()
{
    std::thread([](){ run_async_task(); });
}

除了线程的析构函数会终止我的任务,我不需要任何控制任务,也不需要返回值,它只需要运行它的进程,然后线程应该终止,C线程对象应该被处理掉,我需要什么C11工具?
我看过std::async,但找不到适合我的例子,它似乎是一个相当复杂的系统,我需要以某种方式存储和操作std::future,否则它将成为同步的(如果我的理解是正确的;我没有找到一篇关于std::async的好文章)。

yzuktlbb

yzuktlbb1#

只需在创建后立即将其分离。

std::thread([](){ run_async_task(); }).detach();

一旦分离,线程将不再是可连接的,因此~thread()将无效。This answer讨论了此行为的更多细节。
如下文W.B.所述,std::async将因以下原因而无法工作,从该reference中取出。
如果从std::async获得的std::future具有临时对象生存期(未移动或绑定到变量),则std::future的析构函数将在完整表达式的末尾阻塞,直到异步操作完成

v64noz0r

v64noz0r2#

重新启动一个旧线程,但是有一个巧妙的技巧 *,即如何通过使用std::async来实现“触发并忘记”功能,尽管它返回了阻塞的std::future。主要成分是一个指向返回的std::future的共享指针,该指针在lambda中通过值捕获。导致它的引用计数器递增。这样std::future的析构函数在lambda完成它的工作之前不会被调用,提供了真实的的异步行为。

template <class F>
void call_async(F&& fun) {
    auto futptr = std::make_shared<std::future<void>>();
    *futptr = std::async(std::launch::async, [futptr, fun]() {
        fun();
    });
}
  • 感谢我的一位同事,也是真正的C++MavenMVV,他向我展示了这个技巧。

编辑日期:2023年3月4日

不要在生产代码中使用上面显示的技巧,不幸的是,它有一个问题。它与下面的代码片段非常相似:

...
*futptr = std::async(std::launch::async, [futptr, self = shared_from_this()]() mutable {
    fprintf(stderr, "std::async done.\n");
    futptr.reset();
    fprintf(stderr, "std::async really done.\n");
});
...

其中 std::async really done. 将永远不会被打印。简而言之,futptr.reset()强制std::future析构函数,而这个析构函数等待std::promise完成,但由于函数仍在执行中,因此无法完成。当我们调用reset()时也会发生同样的情况,在这种情况下,我们再次有一个隐式reset()-这次是在futptr的析构函数中。
不过,还是有办法不用std::threaddetach()就能实现“一发不可收拾”:ASIO及其post函数。

相关问题