使用 std::async 时死锁,将来作为成员

Deadlock when using std::async with future as member

本文关键字:将来 成员 死锁 std async 使用      更新时间:2023-10-16

我将我们的应用程序从Objective-C和Cocoa转移到C++。 在Objective-C中,我经常使用Grand Central Dispatch和非常方便的dispatch_async功能。

当移动到 C++11 时,我发现 std::async 是最接近的等价物。 我正在使用它的斯科特迈耶斯变体,以确保它真的是异步调用的:

template<typename F, typename... Ts>
inline auto NLA_async(F&& f, Ts&&... params)
{
return std::async(std::launch::async,
std::forward<F>(f),
std::forward<Ts>(params)...);
}

我了解到,如果未分配返回的未来,该函数实际上不会异步调用,因为未来 d'tor 将等待异步块完成。

void foo()
{
NLA_async([]{ // run long task async });
// future returned from NLA_async not captured 
// -> std::future d'tor waits for block to be finished
}

所以我想我只是将 future 分配给一个类成员,以便它至少在大多数情况下异步调度(不理想,但我认为这是一个快速而肮脏的解决方法(。到目前为止,这运作良好。

但是,我遇到了我还不明白的僵局。 看起来该块可能同时执行两次,这在我的情况下会导致死锁。

你可以在这里看看:

http://coliru.stacked-crooked.com/a/dc4fcbaff370f1b9

谁能解释为什么同时执行两次?

编辑: 在我的特殊情况下,问题是在异步块结束时,代码锁定互斥锁,执行一些工作,然后解锁互斥锁。在这一点上,我们陷入了僵局。看起来正在运行的异步块在完成之前被删除,因为互斥锁保持锁定状态,尽管它不应该(没有 return 语句或任何可以解释为什么它不会解锁互斥锁的东西(。

两个线程异步运行的问题可能与以下事实有关:创建未来并将其分配给成员变量不会一步到位。

首先,创建它并启动线程。然后,在等待第一个线程完成时将其分配给成员变量。

感谢无用指出这一点!