std::future和std::promise
并行开发挺复杂的,特别是在试图用好线程和锁的过程中。如果要用到条件变量或std-atomics(一种无锁开发方式),那就更复杂了。C++0x提供了future和promise来简化任务线程间的返回值操作;同时为启动任务线程提供了packaged_task以方便操作。其中的关键点是允许2个任务间使用无(显式)锁的方式进行值传递;标准库帮你高效的做好这些了。基本思路很简单:当一个任务需要向父线程(启动它的线程)返回值时,它把这个值放到promise中。之后,这个返回值会出现在和此promise关联的future中。于是父线程就能读到返回值。更简单点的方法,参看async()。
标准库中提供了3种future:普通future和为复杂场合使用的shared_future和atomic_future。在本主题中,只展示了普通future,它已经完全够用了。如果我们有一个future
f,通过get()可以获得它的值:
X v = f.get(); // if necessary wait for the value to get computed
如果它的返回值还没有到达,调用线程会进行阻塞等待。要是等啊等啊,等到花儿也谢了的话,get()会抛出异常的(从标准库或等待的线程那个线程中抛出)。
如果我们不需要等待返回值(非阻塞方式),可以简单询问一下future,看返回值是否已经到达:
if (f.wait_for(0))
{
// there is a value to get()
// do something
}
else
{
// do something else
}
但是,future最主要的目的还是提供一个简单的获取返回值的方法:get()。
promise的主要目的是提供一个”put”(或”get”,随你)操作,以和future的get()对应。future和promise的名字是有历史来历的,是一个双关语。感觉有点别扭?请别怪我。
promise为future传递的结果类型有2种:传一个普通值或者抛出一个异常
try {
X res;
// compute a value for res
p.set_value(res);
}
catch (…) { // oops: couldn’t compute res
p.set_exception(std::current_exception());
}
到目前为止还不错,不过我们如何匹配future/promise对呢?一个在我的线程,另一个在别的啥线程中吗?是这样:既然future和promise可以被到处移动(不是拷贝),那么可能性就挺多的。最普遍的情况是父子线程配对形式,父线程用future获取子线程promise返回的值。在这种情况下,使用async()是很优雅的方法。
packaged_task提供了启动任务线程的简单方法。特别是它处理好了future和promise的关联关系,同时提供了包装代码以保证返回值/异常可以放到promise中,示例代码:
void comp(vector& v)
{
// package the tasks:
// (the task here is the standard
// accumulate() for an array of doubles):
packaged_task pt0{std::accumulate};
packaged_task pt1{std::accumulate};
auto f0 = pt0.get_future(); // get hold of the futures
auto f1 = pt1.get_future();
pt0(&v[0],&v[v.size()/2],0); // start the threads
pt1(&[v.size()/2],&v[size()],0);
return f0.get()+f1.get(); // get the results
}
参看:
- Standard: 30.6 Futures [futures]
Anthony Williams:
Moving Futures – Proposed Wording for UK comments 335, 336, 337 and 338.
N2888==09-0078.
Detlef Vollmann, Howard Hinnant, and Anthony Williams
An Asynchronous Future Value (revised)
N2627=08-0137.
Howard E. Hinnant:
Multithreading API for C++0X – A Layered Approach.
N2094=06-0164. The original proposal for a complete threading package..
(翻译:interma)