C ++:std :: async和std :: mutex在Linux上导致死锁,但在Windows上运行?

我刚刚编译了一个在Windows下用于Linux的项目,发现它在某个时刻挂起。 因为我使用std :: async和std :: mutex我的第一个假设是,它可能是一个死锁问题。 不过,我不知道为什么它在Windows上运行良好。 这里是代码:

void BorderExtractor::preprocessImageAsync(const PreprocessingSettings& settings) { _preprocessingMutex.lock(); if (!_preprocessingActive) { _preprocessingActive = true; std::async(std::launch::async, &BorderExtractor::preprocessImage, this, settings); //this point is never reached on linux _preprocessingUpToDate = true; } else { _cachedSettings = settings; _preprocessingUpToDate = false; } _preprocessingMutex.unlock(); } 

这是在Linux下永远不会返回的函数。 它运行,直到asynchronous调用,然后停止。 它几乎看起来好像该函数不是asynchronous启动的,程序等待它返回,什么都不起作用,因为另一个函数会试图locking相同的互斥量。

这是asynchronous调用的函数:

 void BorderExtractor::preprocessImage(PreprocessingSettings settings) { //here some image processing stuff is done _preprocessingMutex.lock(); //this point is never reached on linux if (!_preprocessingUpToDate) { _preprocessingUpToDate = true; _preprocessingMutex.unlock(); std::async(std::launch::async, &BorderExtractor::preprocessImage, this, _cachedSettings); } else { _preprocessingUpToDate = true; _preprocessingActive = false; _preprocessingMutex.unlock(); } } 

它试图locking互斥锁之后的一点是永远不会在linux下达成的。

现在有什么问题? 是我的代码是错误的,还是有什么特别的,我必须注意在Linux上? (编译器标志等)对我来说,这似乎是asynchronous调用是同步的,从而导致死锁。 但为什么要这样

这个电话:

 async(std::launch::async, &BorderExtractor::preprocessImage, this, _cachedSettings); 

有效地同步运行。 这是因为std::async()返回的std::future的析构函数最终会与异步计算结合 – 注意,如果以其他方式获得未来,行为将会不同。

既然你没有保留std::async返回的未来对象,它的生命周期在函数调用返回后立即结束,并且它的析构函数会阻塞,直到异步计算终止 – 这是永远的,因为这似乎会导致死锁。

之所以在Windows上工作,可能是因为你使用的是标准库的非兼容实现(例如VS2013附带的微软实现),其中未来的析构函数不会与异步计算结合 – MS按照Herb Sutter这个(被否决的)提案所说明的理由,故意这样做了。

如果你正在寻找一种即忘即断的方法,考虑std::async()这个替代实现 ,它不会导致返回的将来在销毁时阻塞(由bamboon提供 ):

 template<class Function, class... Args> std::future<typename std::result_of<Function(Args...)>::type> async( Function&& f, Args&&... args) { using R = typename std::result_of<Function(Args...)>::type; auto bound_task = std::bind(std::forward<Function>(f), std::forward<Args>(args)...); auto task = std::packaged_task<R()>{std::move(bound_task)}; auto ret = task.get_future(); auto t = std::thread{std::move(task)}; t.detach(); return ret; } 

作为一个方面说明,避免显式锁定/解锁互斥。 相反,使用RAII包装如std::lock_guard或(如有必要) std::unique_lock ,以确保您的互斥锁将被解锁,即使抛出异常或在提前返回的情况下:

 // The mutex will be unlocked automatically when the function returns. std::lock_guard<std::mutex> lock{_preprocessingMutex}; if (!_preprocessingUpToDate) { _preprocessingUpToDate = true; async(std::launch::async, &BorderExtractor::preprocessImage, this, _cachedSettings); // No need to call unlock() on the mutex! } else { _preprocessingUpToDate = true; _preprocessingActive = false; // No need to call unlock() on the mutex! }