Этот вопрос вдохновлен учебным пособием по асинхронному таймеру из документации boost asio ( link ). Код немного изменен, чтобы сделать эффект более очевидным.
Есть связанный вопрос, Несколько async_wait от наддува Asio deadline_timer . Но я не уверен, относится ли ответ на этот вопрос к моему делу.
Код довольно прост и работает, как и ожидалось, если дублирующая строка закомментирована, как показано ниже.
A steady_timer
с продолжительностью 1s
звонков async_wait
.
Когда истекает срок действия, вызывается обработчик. Внутри обработчика время жизни таймера увеличивается еще на одну секунду, и таймер снова вызывает async_wait
.
Переменная count
из 20 используется для ограничения количества срабатываний таймера.
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
namespace asio = boost::asio;
void bind_handler(const boost::system::error_code& ec,
asio::steady_timer& t,
int count) {
if (count > 0) {
std::cout << "getting " << count << "\n";
t.expires_at(t.expiry() + std::chrono::seconds(1));
t.async_wait(boost::bind(bind_handler, asio::placeholders::error,
boost::ref(t), --count));
}
}
int main() {
asio::io_context io_context(1);
asio::steady_timer t(io_context, std::chrono::seconds(1));
int count = 20;
t.async_wait(boost::bind(bind_handler, asio::placeholders::error,
boost::ref(t), count));
//t.async_wait(boost::bind(bind_handler, asio::placeholders::error,
// boost::ref(t), count));
auto start = std::chrono::steady_clock::now();
io_context.run();
auto end = std::chrono::steady_clock::now();
std::cout
<< std::chrono::duration_cast<std::chrono::seconds>(end - start).count()
<< " seconds passed\n";
return 0;
}
Вывод этого кода показан ниже. Новая строка печатается с каждой проходящей секундой.
getting 20
getting 19
getting 18
...lines...
...omitted...
getting 3
getting 2
getting 1
21 seconds passed
Однако, если две строки в приведенном выше коде не закомментированы, программа ведет себя очень по-разному. Вывод наклеен ниже. Программа печатает все строки от getting 20
до getting 1
в течение секунды, ничего не показывает в течение 40 секунд, а затем печатает последнюю строку.
getting 20
getting 20
getting 19
getting 19
getting 18
getting 18
...lines...
...omitted...
getting 3
getting 3
getting 2
getting 2
getting 1
getting 1
41 seconds passed
Мой вопрос: как многократный рекурсивный вызов async_wait
влияет на поведение программы? Я чувствую, что происходит какая-то гонка данных, но цифры все еще печатаются последовательно. Кроме того, задействован только один поток, как мы видим в конструкторе io_context
.