Reputation: 2733
What is the best implementation for an event loop in C/C++ that manages the call stack well?
They're an easy concept: Wait for an event, handle event, wait for more events.
I was looking back over some old projects and came across a simple (and kinda poor) implementation of a search engine, and my curiosity was sparked about the proper way to do event loops.
At the time I'd done something like this (very) simplified example:
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;
}
This implementation relies on call-chaining to achieve an "event loop". I use quotes because while it's logically an event loop, the call stack continually increases and never unwinds:
wait_for_query____...
/
handle_query_______/
/
wait_for_query_______/
While it works, it's always adding new stack frames onto the stack and eventually, after enough events, it will cause a Stack Overflow error! (haha so meta).
What I want is something like this:
handle_query handle_query
/ \ / \
wait_for_query_______/ \_______/ \_____...
I've always heard that an OS is just a while(true)
loop that gets interrupted, so (since my OS hasn't gotten a SO error recently) here's what I thought would be good:
Replace main with:
while(1)
if (wait_for_query() == 0) break;
return 0;
handle_query
's return to 1But does this actually make it more stack efficient? To my knowledge, while
loops (and loops in general) still produce stack frames in assembly language (since they're all branches in execution with scope/local variables/etc.)
What is the best implementation for an event loop in C/C++ that manages the call stack well?
This question assumes a single threaded event loop. Parallelized answers are acceptable too, but I thought that'd would be a bit much to ask about all at once ;)
Fire away
Upvotes: 4
Views: 7800
Reputation:
The initial solutions is fundamentally broken. Event loop looks something like this:
while (q != QUITE) {
q = wait_for_query();
handle_query(q);
}
It's as simple as this. Which actually agrees with what you described:
They're an easy concept: Wait for an event, handle event, wait for more events.
In initial code, semantically, handling the event, handle_query()
, will never be completed until all future events are also completed, recursively, meaning no event will ever be completed. Which is not what you want.
The detailed might get very complicated, e.g how you get the events? does it blocks or not? how events are dispatched? ... etc.
Upvotes: 4
Reputation: 862
Actually, while
won't generate any new stack frames by itself. Stack frames get created when a call
instruction is issued.
If you make handle_query
return 1
as you mention, then your loop won't grow the stack further than two levels (wait_query
+handle_query
) for each event it processes:
handle_query handle_query
/ \ / \
wait_for_query_______/ \_______/ \_____...
/
/
main_loop
Which looks like the stack structure you were looking for.
Upvotes: 1