Какова лучшая реализация для цикла событий в C / C ++, который хорошо управляет стеком вызовов?
Это простая концепция: ждать события, обрабатывать события, ждать новых событий.
Я оглядывался назад на некоторые старые проекты и наткнулся на простую (и довольно плохую) реализацию поисковой системы, и мое любопытство вызвало правильный способ сделать цикл событий.
В то время я сделал что-то вроде этого (очень) упрощенного примера:
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), вот что я подумал:
Заменить основной на:
while(1)
if (wait_for_query() == 0) break;
return 0;
handle_query
вернемся к 1Но делает ли это на самом деле сделать его более эффективным в стеке? Насколько мне известно, while
циклы (и циклы в целом) по-прежнему создают стековые фреймы на ассемблере (так как все они выполняются с помощью контекста / локальных переменных / и т.
Какова лучшая реализация для цикла событий в C / C ++, который хорошо управляет стеком вызовов?
Этот вопрос предполагает однопоточный цикл обработки событий. Распараллеленные ответы тоже приемлемы, но я подумал, что было бы слишком много спросить обо всем сразу;)
Огонь прочь
Исходные решения принципиально сломанный. Событие петля выглядит примерно так:
while (q != QUITE) {
q = wait_for_query();
handle_query(q);
}
Это так просто. Что на самом деле согласуется с тем, что вы описали:
Это простая концепция: ждать события, обрабатывать события, ждать новых событий.
В исходном коде, семантически, обрабатывая событие, handle_query()
, никогда не завершится, пока все будущие события также не будут завершены, рекурсивно, то есть ни одно событие не будет завершено. Что не то, что вы хотите.
Детализация может быть очень сложной, например, как вы получаете события? это блокирует или нет? как события отправляются? … так далее.
На самом деле, while
не будет генерировать новые кадры стека сам по себе. Кадры стека создаются, когда call
Инструкция выдается.
Если вы делаете handle_query
вернуть 1
как вы упоминаете, тогда ваш цикл не будет увеличивать стек дальше, чем на два уровня (wait_query
+handle_query
) для каждого события оно обрабатывает:
handle_query handle_query
/ \ / \
wait_for_query_______/ \_______/ \_____...
/
/
main_loop
Который выглядит как структура стека, которую вы искали.