使用std :: async并以future作为成员时出现死锁

时间:2018-10-15 15:35:14

标签: c++ asynchronous

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

转到C ++ 11时,我发现std :: async是最接近的等效项。 我正在使用它的Scott Meyers变体,以确保它确实被异步调用:

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)...);
}

我了解到,如果未分配返回的future,则该函数实际上不会被异步调用,因为future 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语句或任何可以解释为什么无法解锁互斥锁的东西)。

1 个答案:

答案 0 :(得分:0)

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

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

感谢无用指出!