我正在编写一些多线程代码并使用promise / future在不同的线程上调用函数并返回其结果。为了简单起见,我将完全删除线程部分:
template <typename F>
auto blockingCall(F f) -> decltype(f())
{
std::promise<decltype(f())> promise;
// fulfill the promise
promise.set_value(f());
// block until we have a result
return promise.get_future().get();
}
这适用于任何返回非void
的函数。获得未来的return语句也适用于void
。但如果f
是void
函数,我无法履行承诺,因为:
promise.set_value(F()); // 错误:无效使用void表达式
是否有一些聪明的方法可以在void
情况下设置内联的值,或者我是否必须编写一个像call_set_value(promise, f)
这样的辅助函数,它具有std::promise<R>
的重载和std::promise<void>
?
答案 0 :(得分:13)
是。功能过载是最干净的解决方案:
set(promise, f);
然后将set
实现为重载函数,如:
template<typename F, typename R>
void set(std::promise<R> & p, F && f) //handle non-void here
{
p.set_value(f());
}
template<typename F>
void set(std::promise<void> & p, F && f) //handle void here
{
f();
p.set_value();
}
答案 1 :(得分:13)
promise
只是一种异步结果提供者。而不是promise
你可以使用包裹可调用对象的packaged_task
,类似于std::function
,除了调用它使得结果可以通过future
获得(当然它处理void
和非空结果之间的差异:
template <typename F>
auto blockingCall(F f) -> decltype(f())
{
std::packaged_task<decltype(f())()> task(std::move(f));
task();
// block until we have a result
return task.get_future().get();
}
N.B。根据当前标准,如果task()
和task.get_future()
发生在不同的线程上,那么此代码会有数据竞争(原来使用保证也是如此),因此您应该先调用get_future()
将任务交给另一个线程。在实践中,它应该对实际实现是安全的,并且存在库问题(LWG 2412)以使其无论如何都有效。