如何分配与std :: future关联的存储?

时间:2012-10-11 07:24:35

标签: c++ asynchronous c++11 future c++-standard-library

获得std::future的一种方法是通过std::async

int foo()
{
  return 42;
}

...

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

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

对于上下文,我看到std::promise的{​​{3}}可能会收到一个分配器,但我不清楚是否可以自定义std::future的分配。 std::async

2 个答案:

答案 0 :(得分:6)

内存由调用std::async的线程分配,您无法控制它是如何完成的。通常情况下,它会由new __internal_state_type的某些变体完成,但不能保证;它可以使用malloc,或者为此目的专门选择的分配器。

从30.6.8p3 [futures.async]:

  

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

“第一个函数”是没有启动策略的重载,而第二个函数是启动策略的重载。

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)就好像在由线程对象表示的新执行线程中调用DECAY_COPY ()在调用async ...

的主题中进行评估

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

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

答案 1 :(得分:6)

仅从std::async的仅仅参数判断,似乎没有办法控制内部std::promise的分配,因此它可以只使用任何东西,尽管可能是std::allocator。虽然我认为理论上它是未指定的,但很可能共享状态是在调用线程内部分配的。我没有在标准中找到关于此事的任何明确信息。最后,std::async是一个非常专业的工具,可以轻松进行异步调用,因此您无需考虑实际上 是否std::promise

为了更直接地控制异步调用的行为,还有std::packaged_task,它确实有一个allocator参数。但仅从标准引用来看,这个分配器是否仅用于为函数分配存储(因为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),它可能只是一个可以连接到{{1}的未定义类型}}

因此,如果确实没有指定std::future如何分配其内部共享状态,那么最好的办法就是为异步函数调用实现自己的工具。考虑到这一点,简单地说,std::packaged_task只是与std::packaged_task绑定的std::function,而std::promise只是在新主题中开始std::async(除了如果没有),这不应该是一个太大的问题。

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

编辑:再次阅读,我认为上面的标准引用确实说明了使用提供的分配器分配了std::promise的共享状态 ,因为它是“内部数据结构”的一部分,无论它们是什么(不一定是真正的std::packaged_task)。所以我认为std::promise应该足以明确控制异步任务std::packaged_task的共享状态。