但是,在现实生活中,我正在针对高可靠性和嵌入式环境。可能甚至没有堆,所以...
struct coroutine_return_type
{
struct promise_type
{
void *operator new(std::size_t sz, char *buf, std::size_t szbuf)
{
if (sz > szbuf)
throw std::bad_alloc{};
return buf;
}
void operator delete(void *)
{
}
// ...
};
// ...
};
coroutine_return_type my_coroutine(char *, std::size_t)
{
// The arguments, char * and std::size_t,
// have been fowrarded to promise_type::operator new
// but here in the coroutine body they aren't used again...
for ( ; ; )
co_yield /* something */;
}
struct coroutine_instance_type
{
char my_coroutine_frame[ /* WHAT? */ ];
coroutine_return_type my_coroutine_instance;
coroutine_instance_type()
: my_coroutine_instance{my_coroutine(my_coroutine_frame, sizeof(my_coroutine_frame))}
{
// ...
}
// ...
};
我想要的
我想要一个编译时表达式,用于返回我的协程大小的上限,以替换/* WHAT? */
。
愚蠢的解决方案
有一种明显愚蠢的方法(不完全)实现我的需求:
子类化std::bad_alloc。然后在我的
operator new
中,将throw std::bad_alloc{}
变为throw std::my_bad_alloc{sz}
。catch块可以调用my_bad_alloc_instance.get_parameter()
来了解operator new
中的sz
是多少。调用
my_coroutine(nullptr, 0)
并捕获异常。
这个方法的愚蠢之处(非穷尽列表):
它不是一个编译时表达式,因为它必须使用throw
“返回”其值,而throw
永远不能在编译时表达式中使用。但是,在我的伪代码中,/* WHAT? */
的替换需要是一个编译时表达式。
它是一个示例,而不是一个上限。假设协程帧的实际分配大小取决于运行时的条件。(现在,我不预计在我的IRL应用程序中会出现不同的协程大小对应不同的运行时条件,但根据C++标准似乎是可能的。)在这种情况下,仅了解传递给operator new
的实际大小是不够的。所需的表达式必须返回一个上限,以表示可能传递给operator new
的最大值。
因此,总结一下:
问题概述
C++语言提供了哪些工具来查询协程帧的大小?理想的工具应该是一个编译时表达式,用于为协程分配非堆内存,或者,同样的工具也可以用于限制堆的数量。
co_await
风格的协程吗?在这种情况下,可能没有堆。如果每个字节和时钟周期都很宝贵,我建议避免使用 C++ 机制,因为它们的性能特性是不确定的,就像你会避免使用dynamic_cast
、typeid
等一样。 - Nicol Bolasco_await
比std::thread
更好。 - cs-co_await
协程不过是一种暂停和恢复函数执行的机制。它们本质上与线程没有任何关系。现在,它们的主要设计目的是促进异步继续使用。但继续假设线程已经存在并且将要执行某些操作,因此您希望在该线程中执行的内容完成后执行此函数。它们不是std::thread
或任何其他线程创建机制的替代品。 - Nicol Bolasco_await
使得编写和推理这样的内容变得更加容易,但可恢复任务并行不像是一个新的研究领域。传统的方法往往涉及显式继续函数或完整的纤维(比任何co_await
协程的堆栈都要大)。co_await
非常适合您的需求,但您必须接受与其相伴随的缺乏控制。 - Nicol Bolas