используйте io_service :: post (boost), когда deadline_timer ожидает

У меня проблема при использовании 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).

Спасибо большое!

2

Решение

На самом деле это довольно сложный пример.

io_service будет работать в главном потоке. Вот порядок действий

Основная тема:

  • Таймер запроса на T0 + 1
  • Таймер запроса на T0 + 2
  • Порожденная нить
  • Выполнить все ожидающие IO (io_service.run())

Вторичная тема:

  • Спать 5 секунд
  • Таймер запроса
  • Таймер запроса

Прежде всего, ничего не будет выполнено в io_service до тех пор io_service.run() называется.

однажды io_service.run() вызывается таймер на 1 секунду в будущем. Когда этот таймер срабатывает, он сначала спит в течение 5 секунд перед печатью 1.

Во время выполнения этого потока вспомогательный поток также запускается и спит в течение 5 секунд. Этот поток настроен и запланирован до выполнения таймера в обработчике для timer1 выполнен. Поскольку обе эти темы спят в течение 5 секунд, «2» и «3» немедленно отправляются на io_service,

Теперь все становится немного сложнее. Кажется вероятным, что тайм-аут для timer2 должен был истечь к настоящему времени (это будет по крайней мере 5 секунд в будущем), но было две команды, непосредственно отправленные на io_service пока он занимался timer1,

Кажется, что в деталях реализации, boost отдает приоритет непосредственно опубликованным действиям, а не действиям таймера крайнего срока.

0

Другие решения

истечение первого таймера блокирует запуск потока io (main), в то время как другой поток отправляет пару элементов в рабочую очередь asio, после завершения обратного вызова таймера 1 обрабатывается истечение второго таймера, что приводит к постановке обратного вызова в очередь. но не выполнено. с «3» & «4», где уже в очереди (в то время как «1» блокировал основной поток), они идут впереди «2»

Суть asio заключается в том, чтобы не блокировать. Поместив длительную работу в обратный вызов первого таймера (спящий режим), вы предотвратили своевременное выполнение потока ввода-вывода. Вы должны перенести эту работу в отдельный поток и опубликовать ее завершение в asio.

0

io_service не дает никаких гарантий относительно порядка вызова обработчиков. Теоретически, обработчики могут вызываться в любом порядке, причем некоторые перестановки значительно маловероятны.

Если обработчики нужно вызывать в очень конкретном порядке, рассмотрите возможность перестройки цепочек асинхронных вызовов таким образом, чтобы обеспечить требуемую цепочку обработчиков. Кроме того, может оказаться необходимым использовать гарантированный порядок вызова обработчика, который нитка обеспечивает. Не пытайтесь контролировать сложные вызовы обработчиков с помощью хрупких снов и таймеров.

0

Ваша первая проблема заключается в том, что вы пытаетесь заблокировать внутри обработчика:

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;
}
0
По вопросам рекламы [email protected]