存储如何与 std::future 分配相关联?
How is the storage associated with std::future allocated?
获得std::future
的一种方法是通过std::async
:
int foo()
{
return 42;
}
...
std::future<int> x = std::async(foo);
在此示例中,如何分配x
异步状态的存储,以及哪个线程(如果涉及多个线程)负责执行分配?此外,std::async
的客户对分配有任何控制权吗?
对于上下文,我看到std::promise
的一个构造函数可能会收到一个分配器,但我不清楚是否可以在std::async
级别自定义std::future
的分配。
内存由调用std::async
的线程分配,您无法控制它是如何完成的。通常它会通过某种new __internal_state_type
变体来完成,但不能保证;它可以使用malloc
,或为此目的专门选择的分配器。
从 30.6.8p3 [futures.async]:
"效果:第一个函数的行为与对第二个函数的调用相同,策略参数为
launch::async | launch::deferred
,F
和Args
参数相同。第二个函数创建与返回的未来对象关联的共享状态。...">
"第一个功能"是没有启动策略的重载,而第二个函数是启动策略的重载。
在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
,但你为什么要这样做呢?
仅从std::async
的论点来看,似乎没有办法控制内部std::promise
的分配,因此它可以使用任何东西,尽管可能是std::allocator
。虽然我想理论上它是未指定的,但共享状态很可能是在调用线程中分配的。我在标准中没有找到有关此事的任何明确信息。最后,std::async
是一个非常专业的工具,用于轻松异步调用,因此您不必考虑任何地方是否真的有std::promise
。
为了更直接地控制异步调用的行为,还有std::packaged_task
,它确实有一个分配器参数。但是从单纯的标准报价来看,这个分配器是否仅用于为函数分配存储(因为std::packaged_task
是一种特殊的std::function
),或者它是否也用于分配内部std::promise
的共享状态,尽管似乎有可能:
30.6.9.1 [期货任务成员]:
效果:构造具有共享状态的新
packaged_task
对象和 使用std::forward<F>(f)
初始化对象的存储任务。这 采用Allocator
参数的构造函数使用它来分配内存 需要存储内部数据结构。
好吧,它甚至没有说下面有一个std::promise
(同样适用于std::async
),它可能只是一个可连接到std::future
的未定义类型。
因此,如果确实没有指定std::packaged_task
如何分配其内部共享状态,则最好的办法可能是实现自己的异步函数调用工具。考虑到,简单地说,std::packaged_task
只是一个与std::promise
捆绑在一起的std::function
,std::async
只是在新线程中启动std::packaged_task
(好吧,除非它没有),这应该不是太大的问题。
但实际上,这可能是规范中的疏忽。虽然分配控制并不适合std::async
,但std::packaged_task
及其对分配器的使用的解释可能更清楚一些。但这也可能是有意为之的,因此std::packaged_task
可以自由使用任何它想要的东西,甚至不需要内部std::promise
。
编辑:再次阅读,我认为上面的标准引用确实说,std::packaged_task
的共享状态是使用提供的分配器分配的,因为它是"内部数据结构">的一部分,无论这些结构是什么(不需要实际的std::promise
,虽然)。所以我认为std::packaged_task
应该足以显式控制异步任务std::future
的共享状态。
- 将数组的地址分配给变量并删除
- vector.resize()中的分配错误
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- Win32编译器选项和内存分配
- 函数中堆分配的效果与缺少堆分配的情况
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 获取字符串的长度并将其分配给数组
- 将地址分配给本地指针后,公共对象的变量将消失
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 我在二维向量中是否正确分配了内存
- 正在尝试重载二进制搜索树分配运算符
- 关联容器的下界复杂性:成员函数与非成员函数
- GlobalAlloc而不是其他分配方法
- 自定义先决条件对移动分配运算符有效吗
- 我可以重新分配/覆盖std::字符串吗
- 在c++中使用动态分配的问题
- 解除分配与 C++ 中的结构关联的所有内存
- 存储如何与 std::future 分配相关联?