Форум программистов, компьютерный форум, киберфорум
Boost C++
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.62/13: Рейтинг темы: голосов - 13, средняя оценка - 4.62
В астрале
Эксперт С++
8033 / 4790 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
1

Boost ASIO таймер работает не так как ожидается

01.06.2021, 21:06. Показов 2689. Ответов 3

Есть код, который ставит таймер на запись в сокет, когда пришел хендлер обновляет таймер, после чего запускает таймер на получение (за учетом времени прошедшего на момент записи в сокет), после чтения отменяет таймер. Когда тестирую у себя локально - все ок. Когда тестирую на кластере, где запущено еще штук 600 процессов - получаю следующую картину:

Jun 1 13:03:37 s9912-pos-service-85d547989f-hwmbs pos_service@1[11] network.cpp: 772 on response: 0:system - Success is_open: true, do cancel timer
Jun 1 13:03:37 s9912-pos-service-85d547989f-hwmbs pos_service@1[11] network.cpp: 775 response: 200 length: 430 chunked: true
Jun 1 13:03:37 s9912-pos-service-85d547989f-hwmbs pos_service@1[11] network.cpp: 480 On timeout: 0:system - Success
Jun 1 13:03:37 s9912-pos-service-85d547989f-hwmbs pos_service@1[11] network.cpp: 513 read/write phase -> close socket
Jun 1 13:03:37 s9912-pos-service-85d547989f-hwmbs pos_service@1[11] network.cpp: 731 run finished
Jun 1 13:03:37 s9912-pos-service-85d547989f-hwmbs pos_service@1[11] network.cpp: 219 Elapsed: 48 ms for phase: request

Таймаут на фазу запроса (запрос + ответ) - 10мс.
Кусок кода http клиента:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
void client_peer::do_request_phase(const pion::http::request_ptr& http_request)
{
   phase_t phase = phase_t::request;
   state_ = state_t::request_in_process;
   http_response_.reset();
   const bool result = do_phase
   (
      phase,
      [this, &http_request]()
      {
         do_send_phase(http_request);
         do_receive_phase(http_request);
      },
      std::bind(&this_type::do_resend, this, std::cref(http_request)),
      std::bind(&basic_policy::reconnect_on_request_timeout, std::ref(policy_))
   );
   if (!result)
   {
      return;
   }
   state_ = state_t::wait;
}
 
void client_peer::do_send_phase(const pion::http::request_ptr& http_request)
{
   set_timeout(phase_t::request);
   pion::http::request_writer_ptr writer(pion::http::request_writer::create(tcp_conn_, http_request));
   writer->send(boost::bind(&this_type::on_finish_write, this));
   run();
}
 
void client_peer::do_receive_phase(const pion::http::request_ptr& http_request)
{
    set_timeout(phase_t::request);
    pion::http::response_reader_ptr reader
    (
        pion::http::response_reader::create
        (
           tcp_conn_, *http_request, boost::bind(&this_type::on_finish_read, this, _1, _2, _3)
        )
    );
    reader->set_timeout(0);
    reader->set_max_content_length(MAX_HTTP_CONTENT_LENGTH);
    reader->receive();
    run();
}
 
void client_peer::set_timeout(phase_t phase)
{
   const auto& timeout = timeouts_[phase];
   if (timeout.is_special)
   {
      return;
   }
   if (timeout.type == timeout_type_t::full_operation || timeout.type == timeout_type_t::attempt_full_operation)
   {
      wait_timer_.expires_at(timeout.dead_time);
   }
   else /* if (timeout.type == timeout_type_t::operation || timeout.type == timeout_type_t::attempt) */
   {
      if (!timeout.timeout.is_special())
      {
         wait_timer_.expires_from_now(timeout.timeout);
      }
      else
      {
         wait_timer_.expires_at(dt::ptime());
      }
   }
}
 
bool client_peer::do_phase(phase_t phase, const std::function<void()>& phase_fn, const std::function<void()>& retry_fn, const std::function<bool()>& policy_fn)
{
   try
   {
      run_with_elapsed_calculation(phase, phase_fn);
      modify_timeout(phase, false);
   }
   catch (const timeout_error& e)
   {
      wait_timer_.expires_at(dt::ptime());
      if (tcp_conn_ && tcp_conn_->is_open())
      {
         tcp_conn_->close();
      }
      modify_timeout(phase, true);
      if (state_ != state_t::connect_final_error && policy_fn())
      {
         LINFO << "timeout is not critical due policy";
         retry_fn();
         return false;
      }
      else if (request_state_.empty())
      {
         request_state_ = network::attempts_interrupted;
      }
      throw;
   }
   return true;
}
run запускает ios.run и ждет возврата.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
01.06.2021, 21:06
Ответы с готовыми решениями:

HTTPS запрос к Telegram API с Boost Beast & Boost Asio (Не работает)
#include &quot;root_certificates.hpp&quot; #include &lt;boost/beast/core.hpp&gt; #include...

Job работает не так, как ожидается
Добрый день. Возникла такая проблема. Вывел загрузку данных в модальное окно, заполняется textarea...

#define работает не так, как ожидается
Здравствуйте. Подскажите, пожалуйста, почему в таком случае некорректно использовать #define: ...

Почему цикл работает не так, как ожидается?
Двумя способами реализовал цикл, который увеличивает годовую зарплату на 10% при нажатии 'y' до тех...

3
Заблокирован
04.06.2021, 09:13 2
Проблема не ясна. Отменил таймер, но коллбэк всё равно вызвался? Значит, отменяешь неправильно - там недостаточно сделать cancel, поскольку обработчик может быть уже в очереди. Т. е. таймер уже сработал, cancel отменяет только само срабатывание, но не вызов коллбэка если он уже в очереди. Заводи флаг отмены на каждое ожидание на таймере и отмену делай так: cancel = true, wait_timer_.cancel(); Затем проверяешь этот флаг в коллбэке таймера: выставлен - ничего не делаешь, просто выходишь.
0
Любитель чаепитий
3561 / 1667 / 513
Регистрация: 24.08.2014
Сообщений: 5,641
Записей в блоге: 1
08.06.2021, 09:30 3
Цитата Сообщение от ForEveR Посмотреть сообщение
run запускает ios.run и ждет возврата.
в одном потоке запускается?

ну вообще конкретно-то в чём проблема?
что отменил таймер, а таймаут всё равно сработал?
в документации сказано:
Remarks
If the timer has already expired when cancel() is called, then the handlers for asynchronous wait operations will:

* have already been invoked; or
* have been queued for invocation in the near future.
These handlers can no longer be cancelled, and therefore are passed an error code that indicates the successful completion of the wait operation.
мб стоит глянуть, как он отменяется. (может через какой-нибудь ios.post([&] () { timer.cancel(); });, например.)
ещё можешь попробовать собрать asio с дебажными логами или BOOST_ASIO_ENABLE_HANDLER_TRACKING.
1
В астрале
Эксперт С++
8033 / 4790 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
18.06.2021, 02:00  [ТС] 4
Цитата Сообщение от GbaLog- Посмотреть сообщение
в одном потоке запускается?
В одном.
Цитата Сообщение от GbaLog- Посмотреть сообщение
ну вообще конкретно-то в чём проблема?
что отменил таймер, а таймаут всё равно сработал?
Что идет задержка в какое-то слишком большое кол-во МС.
Цитата Сообщение от GbaLog- Посмотреть сообщение
мб стоит глянуть, как он отменяется. (может через какой-нибудь ios.post([&] () { timer.cancel(); });, например.)
Просто wait_timer_.cancel();
Цитата Сообщение от GbaLog- Посмотреть сообщение
ещё можешь попробовать собрать asio с дебажными логами или BOOST_ASIO_ENABLE_HANDLER_TRACKING.
Вариант, спасибо. Но пока решили что это не столь критично и проблема скорее всего в том что тестовый сервер просто не успевает в переключение контекста. В бою подобной проблемы не видел за несколько недель.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
18.06.2021, 02:00

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Условие в цикле do while работает не так, как ожидается
Проблема в условие цикла. Вот Код.// ConsoleApplication4.cpp: определяет точку входа для...

Почему malloc работает не так, как ожидается?
int main() { int* p =malloc(sizeof(int)); p=5; printf(&quot;%s\n&quot;,strerror(errno)); ...

ConstraintSet работает не так как ожидается в Handler
Делаю визуализацию сортировки. Сначала хочу реализовать swap. Два элемента подсвечиваются красным,...

Boost::Asio Сделать так, чтобы сервер отвечал на запросы из браузера
Добрый день! Взял один из примеров Boost по асинхронным серверам. Данный код сервера-клиента...

Boost::asio::deadline_timer не работает асинхронно
Код void print1(const boost::system::error_code&amp; e) { std::cout &lt;&lt; &quot;Hello, world!\n&quot;; } ...

Код работает не так, как ожидается (найти и исправить ошибки)
#include &lt;stdio.h&gt; #include &lt;conio.h&gt; #include &lt;string.h&gt; char deletika(char a, long ot, long...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.