2012-10-11 31 views
11

一种方式来获得一个std::future通过std::async如何分配与std :: future相关的存储?

int foo() 
{ 
    return 42; 
} 

... 

std::future<int> x = std::async(foo); 

在这个例子中,是如何分配给x的异步状态的存储,以及线程(如果有多个线程参与)负责执行分配?此外,std::async的客户是否对分配有任何控制权?

对于背景下,我看到的std::promiseone of the constructors可能会收到一个allocator,但如果它是可以定制在std::async水平std::future的分配目前还不清楚我。

回答

5

仅仅从std::async的简单论据来看,似乎没有办法控制内部std::promise的分配,因此它可以只使用任何东西,尽管可能是std::allocator。虽然我在理论上猜想它没有指定,但共享状态很可能是在调用线程内分配的。我没有在标准中找到有关此事的明确信息。最后std::async是一个非常容易异步调用的专用工具,因此您不必考虑是否存在任何地方实际上 a std::promise

为了更直接地控制异步调用的行为,还有std::packaged_task,它确实有一个分配器参数。但是从纯粹的标准报价来看,这个分配器是否仅仅用于为函数分配存储空间并不十分清楚(因为std::packaged_task是一种特殊的std::function),或者它也用于分配内部的共享状态std::promise似乎有可能:

30.6.9.1 [futures.task.members]:

影响:构造了一个新的packaged_task对象与共享状态和 初始化对象与std::forward<F>(f)存储任务。采用Allocator参数的 构造函数使用它来分配存储内部数据结构所需的内存 。

好了,它甚至不说有一个std::promise下(同样为std::async),它可能只是一个未定义的类型连接到std::future

因此,如果确实没有指定如何分配其内部共享状态,最好的办法可能是实现自己的设施进行异步函数调用。考虑到,简单地说,std::packaged_task只是一个std::functionstd::promisestd::async捆绑在一个新的线程(当然,除非没有),只是开始std::packaged_task,这应该不是太多的问题。

但实际上这可能是规范中的疏忽。虽然分配控制并不适合std::async,但std::packaged_task的解释及其对分配器的使用可能会更清楚一些。但这也可能是故意的,所以std::packaged_task可以随意使用,甚至不需要在内部使用std::promise

编辑:重读它,我觉得上面的标准报价确实说,该std::packaged_task的共享状态使用提供的分配程序分配,因为它是‘内部数据结构’的一部分,不管这些是什么(虽然不需要是实际的std::promise)。所以我认为std::packaged_task应该足够显式控制异步任务的共享状态std::future

5

内存由调用std::async的线程分配的,你必须在它是如何做任何控制。通常情况下,它将通过new __internal_state_type的一些变体完成,但没有保证;它可以使用malloc,或专门为此目的选择的分配器。

从30.6.8p3 [futures.async]:

“效果:第一个函数的行为相同于第二函数调用与launch::async | launch::deferred的策略参数,并用于FArgs相同的参数。第二个函数创建与返回的未来对象关联的共享状态...“

”第一个功能“是没有启动策略的过载,而第二个功能是带启动策略的超载。

std::launch::deferred的情况下,没有其他线程,所以一切都必须发生在调用线程上。在std::launch::async的情况下,30.6.8p3接着说:

- 如果policy & launch::async非零 - 调用INVOKE (DECAY_COPY (std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)(20.8.2,30.3.1.2),就好像在一个新的执行线程通过一个代表线程对象,在调用async的线程中对DECAY_COPY()的调用进行评估。 ...

我已经添加了重点。由于函数和参数的副本必须在调用线程中发生,这基本上要求共享状态由调用线程分配。

当然,你可以编写一个启动新线程的实现,等待它分配状态,然后返回一个引用它的future,但为什么你会这样?

+0

它在哪里保证调用线程分配存储?好的,这很可能,但我仍然希望看到标准的报价。 –

+0

更新的答案更详细。 –

+0

确实,这似乎很清楚,我忽略了这一点。但是,像你现在这样在你的回答中指出这一点不能造成任何伤害。感谢和+1。 –