суббота, 10 сентября 2011 г.

timer revisited

В выложенной недавно версии 0.3.5 реализован "канонический" вариант работы с таймером (ma::echo::server::session). Данный вариант принципиально отличается от предыдущего (!). В прошлом я намеренно сужал API asio::deadline_timer до Java-вского ScheduledExecutorService, дабы иметь в кармане решение и для Java. Однако, с asio::deadline_timer можно работать эффективнее.

Нужно заметить, что мой варинт отличается от того, что предложил автор Asio:
1. нет таких "подвывертов", как deadline_.expires_at(boost::posix_time::pos_infin);
2. нет явных обращений к now(): deadline_.expires_at() <= deadline_timer::traits_type::now().
3. все обыгрывается за счет двух булевых флагов - их можно было заменить одной переменной с тремя состояниями, но с флагами получилось читабельнее.

P.S. А для ScheduledExecutorService можно сделать все в точности так же и никакого "сужения" не нужно было вовсе 8)

8 комментариев:

niXman комментирует...

пытаясь понять как сейчас работает таймер, обнаружил ошибку копипаста. а заключается ошибка в том, что в методе session::apply_socket_options() переменная-член socket_recv_buffer_size_ используется для задания размера как буфера отправки, так и приема. хотя есть вторая переменная socket_send_buffer_size_.

по поводу таймера - я так и не осилил. не могли бы Вы описать алгоритм типа того, как это сделано в примерах asio. без графиков, конечно.

спасибо 8)

Marat Abrarov комментирует...

обнаружил ошибку копипаста
Спасибо, исправил.

не могли бы Вы описать алгоритм типа того, как это сделано в примерах asio.
Алгоритм такой же как и в приведенном примере из документации Asio. Почти копия. Отличие состоит в использовании флагов, поясняющих состояние "асинхронного ожидания" и таймера. На основе этих флагов обработчик handle_timer решает был ли он отменен, и, если был отменен, то стоит ли вновь запускать асинхронное ожидание.

niXman комментирует...

ага. понял.
спасибо.

niXman комментирует...

еще раз более углубленно изучил server::session, и признаюсь, это действительно _прямая_ идея и реализация! браво!

спасибо за труд.

Marat Abrarov комментирует...

действительно _прямая_ идея и реализация

Если Вы про таймер, то это лишь улучшенный пример из документации Asio.

А вот с логикой, состояниями и переходами получилось довольно развесисто из-за необходимости учитывать изменение внутреннего состояния (intern_state_) в каждом handle_*. Но другого пути в общем-то и нет (зато "отзывчато" должно быть). Разве что как-то перенести это на MSM.

niXman комментирует...

я в основном, и в частности о идее использования машины состояний. это здорово!

Marat Abrarov комментирует...

о идее использования машины состояний

Обратите внимание: используются несколько КА:
1. extern_state_ - внешний КА, определяющий допустимые воздействия извне;
2. intern_state_ - основной внутренний КА, так сказать, lifecycle of session;
3. read_state_ - чтение из сокета;
4. write_state_ - запись в сокет;
5. timer_state_ - ожидание на таймере + дополнительно используются вложенные состояния определяемые флагами timer_wait_cancelled_ и timer_turned_.

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

Что-то не нашел литературы по таким вопросам. Было что-то по коммуникационному оборудованию, но слишком далекое и сложное.

Самое сложное - взаимодействие между КА. Трудно не попасть в цикл и трудно сделать код простым/коротким.

Надо добавить, что в примерах Asio все внутренние флаги по сути являются зачатками КА.

Marat Abrarov комментирует...

Что-то не нашел литературы по таким вопросам. Было что-то по коммуникационному оборудованию, но слишком далекое и сложное.

Вот "оно". Буду читать на досуге "до просветления".

Заодно вот еще интересная статья.