Мы должны часто вызывать метод для выполнения некоторых вычислений (около 20 раз в секунду). Это синхронизированный вызов. Вызывающий должен получить результат как можно скорее. Но этот процесс вычисления иногда занимает больше времени, чем ожидалось. Мы не хотим ничего менять. Мы просто хотим добавить какой-то механизм мониторинга, чтобы флаг приложения текущим вычислением был тайм-аутом, когда он переходит в течение ожидаемого периода времени.
У нас есть два варианта:
Опция 1:
создайте поток мониторинга на уровне класса, и он будет работать в течение всего срока службы приложения. Он начнет следить за тем, чтобы производительность метода вычислений всякий раз, когда он вызывается. Он будет сброшен при возврате вызова:
monitorThread.startMonitoring();
doComputation();
monitorThread.stopMonitoring();
Когда вызывается startMonitoring(), working
флаг будет установлен в true, а время начала будет установлено на текущее время на этом мониторе. он сможет узнать, является ли текущее состояние тайм-аутом или нет, когда он просыпается.
Когда вызывается stopMonitoring(), этот working
флаг будет установлен в false, а monitorThread не будет проверять таймаут.
Вариант 2:
использовать boost dead_timer:
boost::asio::deadline_timer timer(io_service);
timer.expires_from_now(boost::posix_time::seconds(1));
timer.async_wait(handler);
doComputation();
timer.cancel();
Я не уверен, что опция dateline_timer будет работать для нас:
РЕДАКТИРОВАТЬ:
1. Если я использую следующий код внутри тела метода, обработчик будет вызван текущим потоком, а doComput() также будет работать в одном потоке. В случае doComput() зависать, как вызван обработчик?
boost::asio::deadline_timer timer(io_service);
timer.expires_from_now(boost::posix_time::seconds(1));
timer.async_wait(handler);
io_service.run(); // new added
doComputation(); // <<---- may hung sometime
timer.cancel();
2. Чтобы повторно использовать таймер и минимизировать количество потоков. Я должен создать экземпляр io_service в начале, т.е. поставить boost::asio::deadline_timer timer(io_service);
в конструкторе. А также позвоните io_service.run();
в новом выделенном потоке (и пусть он умрет после вызова)? или просто вызвать его в главном потоке init, потому что io_service.run() начнет новый поток в любом случае? В том месте, где используется таймер, достаточно следующего фрагмента кода:
timer.cancel();
timer.expires_from_now(boost::posix_time::seconds(1));
timer.async_wait(handler);
doComputation(); // <<---- may hung sometime
timer.cancel();
Я прав?
могу ли я определить таймер на уровне класса и повторно использовать его во время всего сеанса работы приложения?
Да, вы можете повторно использовать таймер, т. Е. Снова вызвать expires_from_now() и async_wait() (но прочитайте ссылку, чтобы понять их поведение!).
вызывает ли вызов async_wait() новый поток в фоновом режиме? если да, возможно ли повторное использование этого потока снова и снова?
Нет (но в любом случае это деталь реализации). handler
будет вызван из потока, выполняющего io_service::run()
.
Следуя вашему EDIT:
Настоятельно рекомендуется ознакомиться с документацией Asio. Обратите внимание, что io_service::run()
является блокирующим вызовом - он блокируется до тех пор, пока не будут вызваны все обработчики завершения. Вы можете рассматривать это как "цикл сообщений". Как правило, один вызывает его из выделенного потока. В качестве альтернативы можно опросить io_service
вручную, вызывая poll()/poll_one() в некоторых других циклах, специфичных для приложения.
io_service :: run() возвращается, когда он больше не работает, то есть нет ожидающих асинхронных операций и обработчиков завершения для отправки. Чтобы этот цикл сообщений выполнялся на протяжении всего срока службы вашего модуля (чтобы вы могли выполнять операции async.), Вам необходимо связать io_service::work
с io_service
.
io_service::run()
в потоке в течение всего срока службы приложения (или модуля). Затем вы можете использовать этотio_service
для любого количества объектов Asio (таймеры, сокеты и т. Д.).