在调用堆栈上很好的 C/C++ 中的事件循环实现
Posted
技术标签:
【中文标题】在调用堆栈上很好的 C/C++ 中的事件循环实现【英文标题】:Implementations for event loop in C/C++ that's nice on the call stack 【发布时间】:2015-10-24 23:04:18 【问题描述】:TL;DR
在 C/C++ 中可以很好地管理调用堆栈的事件循环的最佳实现是什么?
为什么? 基准/比较? 文学/出版物/文档?事件循环,问题
它们是一个简单的概念:等待事件、处理事件、等待更多事件。
我在回顾一些旧项目时发现了一个简单(而且有点糟糕)的搜索引擎实现,我对正确的事件循环方式引发了我的好奇心。 p>
当时我做了这样(非常)简化的例子:
int wait_for_query();
int handle_query();
int main(int argc, const char** argv)
return wait_for_query();
int wait_for_query()
// Do some stuff
return handle_query();
int handle_query()
// Handle it
// if query is quit, return quit();
return wait_for_query();
int quit()
return 0;
此实现依赖于调用链来实现“事件循环”。我使用引号是因为虽然它在逻辑上是一个事件循环,但调用堆栈会不断增加并且永远不会展开:
wait_for_query____...
/
handle_query_______/
/
wait_for_query_______/
虽然它有效,但它总是将新的堆栈帧添加到堆栈中,最终,在发生足够多的事件后,它会导致 堆栈溢出 错误! (哈哈,太元了)。
我想要的是这样的:
handle_query handle_query
/ \ / \
wait_for_query_______/ \_______/ \_____...
到目前为止我得到了什么
我一直听说操作系统只是一个被中断的while(true)
循环,所以(因为我的操作系统最近没有出现 SO 错误)这是我认为好的:
将 main 替换为:
while(1)
if (wait_for_query() == 0) break;
return 0;
将handle_query
的返回改为1
但这实际上会提高堆栈效率吗?据我所知,while
循环(以及一般的循环)仍然会以汇编语言生成堆栈帧(因为它们都是使用范围/局部变量/等执行的分支)
很好地管理调用堆栈的 C/C++ 事件循环的最佳实现是什么?
为什么? 基准/比较? 文学/出版物/文档?注意事项
这个问题假设一个单线程事件循环。并行化的答案也是可以接受的,但我认为一次询问所有问题会有点多;)
开火
【问题讨论】:
while 循环不会随时间增加每次迭代的堆栈使用量。 分支不产生堆栈帧,只产生调用。您的优化器甚至有可能使用分支进行尾调用,以避免堆栈使用,但语言不保证这种优化会发生。 你可能还想看看“Continuation-Passing Style”。 嗯好吧,所以至少我知道 while 循环可以工作并且在堆栈上很好,但它是最好的解决方案吗? @BenVoigt 感谢您的参考! 您想要(C 语言或 C++ 语言)或(C 语言和 C++ 语言)的解决方案?没有C/C++
语言。
【参考方案1】:
最初的解决方案从根本上被破坏了。 Event loop 看起来像这样:
while (q != QUITE)
q = wait_for_query();
handle_query(q);
就这么简单。这实际上与您所描述的一致:
它们是一个简单的概念:等待事件、处理事件、等待更多事件。
在初始代码中,从语义上讲,处理事件handle_query()
将永远不会完成,直到所有未来事件也递归完成,这意味着永远不会完成任何事件。这不是你想要的。
细节可能会变得非常复杂,例如您如何获得事件?它是否阻塞?事件是如何分派的? ...等等。
【讨论】:
我有一个关于这个问题的完整 EventLoop 示例:How would you implement a basic event-loop?。【参考方案2】:实际上,while
本身不会生成任何新的堆栈帧。发出call
指令时会创建堆栈帧。
如果你让handle_query
返回1
就像你提到的那样,那么对于它处理的每个事件,你的循环不会将堆栈增长超过两级 (wait_query
+handle_query
):
handle_query handle_query
/ \ / \
wait_for_query_______/ \_______/ \_____...
/
/
main_loop
这看起来像您正在寻找的堆栈结构。
【讨论】:
以上是关于在调用堆栈上很好的 C/C++ 中的事件循环实现的主要内容,如果未能解决你的问题,请参考以下文章