У меня проблема при использовании deadline_timer и io_service :: post, как показано ниже:
#include "boost/asio.hpp"#include "boost/thread.hpp"int main()
{
boost::asio::io_service io_service;
boost::asio::deadline_timer timer1(io_service);
boost::asio::deadline_timer timer2(io_service);
timer1.expires_from_now(boost::posix_time::seconds(1));
timer1.async_wait([](const boost::system::error_code& error) {
boost::this_thread::sleep(boost::posix_time::seconds(5));
printf("1 ");
});
timer2.expires_from_now(boost::posix_time::seconds(2));
timer2.async_wait([](const boost::system::error_code& error) {
printf("2 ");
});
boost::thread t([&io_service]() {
boost::this_thread::sleep(boost::posix_time::seconds(5));
io_service.post([]() {
printf("3 ");
});
io_service.post([]() {
printf("4 ");
});
});
io_service.run();
t.join();
getchar();
return 0;
}
Я думаю, что результат «1 2 3 4», но результат «1 3 4 2». Любой может показать мне, как выполняется обратный вызов timer2 (печать «2») до того, как результат «1 2 3 4» с библиотекой наддува (и не изменяет время истечения времени timer1 и timer2).
Спасибо большое!
На самом деле это довольно сложный пример.
io_service
будет работать в главном потоке. Вот порядок действий
Основная тема:
io_service.run()
)Вторичная тема:
Прежде всего, ничего не будет выполнено в io_service
до тех пор io_service.run()
называется.
однажды io_service.run()
вызывается таймер на 1 секунду в будущем. Когда этот таймер срабатывает, он сначала спит в течение 5 секунд перед печатью 1.
Во время выполнения этого потока вспомогательный поток также запускается и спит в течение 5 секунд. Этот поток настроен и запланирован до выполнения таймера в обработчике для timer1
выполнен. Поскольку обе эти темы спят в течение 5 секунд, «2» и «3» немедленно отправляются на io_service
,
Теперь все становится немного сложнее. Кажется вероятным, что тайм-аут для timer2
должен был истечь к настоящему времени (это будет по крайней мере 5 секунд в будущем), но было две команды, непосредственно отправленные на io_service
пока он занимался timer1
,
Кажется, что в деталях реализации, boost отдает приоритет непосредственно опубликованным действиям, а не действиям таймера крайнего срока.
истечение первого таймера блокирует запуск потока io (main), в то время как другой поток отправляет пару элементов в рабочую очередь asio, после завершения обратного вызова таймера 1 обрабатывается истечение второго таймера, что приводит к постановке обратного вызова в очередь. но не выполнено. с «3» & «4», где уже в очереди (в то время как «1» блокировал основной поток), они идут впереди «2»
Суть asio заключается в том, чтобы не блокировать. Поместив длительную работу в обратный вызов первого таймера (спящий режим), вы предотвратили своевременное выполнение потока ввода-вывода. Вы должны перенести эту работу в отдельный поток и опубликовать ее завершение в asio.
io_service
не дает никаких гарантий относительно порядка вызова обработчиков. Теоретически, обработчики могут вызываться в любом порядке, причем некоторые перестановки значительно маловероятны.
Если обработчики нужно вызывать в очень конкретном порядке, рассмотрите возможность перестройки цепочек асинхронных вызовов таким образом, чтобы обеспечить требуемую цепочку обработчиков. Кроме того, может оказаться необходимым использовать гарантированный порядок вызова обработчика, который нитка обеспечивает. Не пытайтесь контролировать сложные вызовы обработчиков с помощью хрупких снов и таймеров.
Ваша первая проблема заключается в том, что вы пытаетесь заблокировать внутри обработчика:
timer1.expires_from_now(boost::posix_time::seconds(1));
timer1.async_wait([](const boost::system::error_code& error) {
boost::this_thread::sleep(boost::posix_time::seconds(5)); // <--- HERE
printf("1 ");
});
Что происходит в приведенном выше коде, что после timer1
ждет одну секунду, он отправляет обратный вызов io_service
, Внутри io_service::run
Функция этого обратного вызова выполняется, но это происходит внутри основного потока, поэтому он останавливается на пять секунд, предотвращая timer2
от размещения своего обработчика для выполнения в io_service
, Это происходит до шестой секунды выполнения программы (6 = 5 + 1).
Тем временем нить t
выполняется и на пятой секунде выполнения программы отправляет эти два printf («3») и printf («4») в io_service
,
boost::thread t([&io_service]() {
boost::this_thread::sleep(boost::posix_time::seconds(5));
io_service.post([]() {
printf("3 ");
});
io_service.post([]() {
printf("4 ");
});
});
Однажды обработчик из timer1
разблокирует, это позволяет timer2
отправить свой обработчик io_service
, Это снова происходит на шестой секунде выполнения программы, то есть когда printf("3")
а также printf("4")
уже были опубликованы!
В общем, я считаю, что вы ищете это:
#include "boost/asio.hpp"#include "boost/thread.hpp"
int main()
{
boost::asio::io_service io_service;
boost::optional<boost::asio::io_service::work> work(io_service);
boost::asio::deadline_timer timer1(io_service);
boost::asio::deadline_timer timer2(io_service);
timer1.expires_from_now(boost::posix_time::seconds(1));
timer1.async_wait([](const boost::system::error_code& error) {
printf("1 ");
});
timer2.expires_from_now(boost::posix_time::seconds(2));
timer2.async_wait([](const boost::system::error_code& error) {
printf("2 ");
});
boost::thread t([&io_service, &work]() {
boost::this_thread::sleep(boost::posix_time::seconds(5));
io_service.post([]() {
printf("3 ");
});
io_service.post([&work]() {
printf("4 ");
work = boost::none;
});
});
io_service.run();
t.join();
return 0;
}