Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
class op_performer : public so_5::agent_t {
// Отложенное сообщение для ограничения времени операции.
struct timeout final : public so_5::signal_t {};
// Состояние ожидания следующей операции.
state_t st_free{this};
// Состояние выполнения операции.
state_t st_working{this};
... // возможно, еще и вложенные подсостояния для st_working.
void so_define_agent() override {
// Подписываемся на отложенное сообщение в st_working
// дабы отменить операцию.
st_working.event(&op_performer::on_timeout);
...
}
void on_perform_operation(mhood_t<start_operation> cmd) {
// Получили команду на начало новой операции.
this >>= st_working;
// Ограничиваем время выполнения операции.
so_5::send_delayed<timeout>(this, 25s);
... // Начинаем операцию.
}
void on_completion(mhood_t<completion_message> cmd) {
... // Завершение операции и отсылка ответа кому нужно.
this >>= st_free; // Возвращаемся в исходное состояние.
}
void on_timeout(mhood_t<timeout>) {
... // Отменяем выполнение операции.
... // Отсылаем отрицательный ответ кому нужно.
this >>= st_free; // Возвращаемся в исходное состояние.
}
...
};class op_performer : public so_5::agent_t {
...
so_5::timer_id_t timeout_timer_;
...
void so_define_agent() override {
st_free.on_enter([this]{ timeout_timer_.reset(); });
st_working.on_enter([this] {
timeout_timer_ = so_5::send_periodic<timeout>(this, 25s, 0s);
});
...
}
};Маркировать таймаут идентификатором задачи, к которой он относится.Как раз такой способ первым в статье и описан :) И это, кстати говоря, один из возможных подходов к решению проблемы отмены отложенных сообщений. Если пусть с отзывными сообщениями зайдет в тупик, то можно будет сделать просто какой-то штатный механизм в SObjectizer-е, который будет отсылать отложенные сообщения с автоматической генерацией для них ID-шников.
Обеспечить для события истечения таймаута гарантии доставки: очередь с приоритетами или выделенная очередь и т.д.ИМХО, здесь даже не в реальном времени дело, а в самом факте существования очереди. Т.е. как только у нас может выстроится комбинация сообщений (completion_message, start_operation, timeout) так сразу же мы натыкаемся на эту проблему. Причем, у нас реально может быть правильный порядок появления сообщений: completion_message в момент времени t, start_operation в момент времени (t+1us) и timeout в момент времени (t+2us). Не говоря уже о том, что если мы работаем не в рамках ОС реального времени, а в обычной многозадачной системе, то мы запросто можем наткнуться на ситуацию, когда в момент времени t возникает timeout, но это сообщение не успевает встать в очередь, поскольку нить таймера прерывают (или же в попытке захватить замок очереди нить таймера оказывается не первой). А в очередь встает completion_message в момент времени (t+1us), а затем start_message в момент времени (t+2us). И лишь затем туда попадет timeout.
Как раз такой способ первым в статье и описан :)
А вот как его красиво оформить…Возможно, это будет что-то похожее на so_5::extra::async_op::time_limited.
РТ — это, так сказать, аспект или, если угодно, cross-cutting concern, и необязательно «пронизывает весь код».
2. Если уж пошла такая пьянка, то то, что таймаут от одной операции прерывает другую операцию — это баг. А возможность такого развития событий — архитектурный просчет.
Вот как-то так, надеюсь, без обид.
отмена таймера (или игнорирование «старых» сообщений от таймеров) очень нужны и важныМы тут сталкиваемся с асинхронной природой взаимодействия между агентами (ну или вообще акторами в Модели Акторов). Актор A может попросить актора B выполнить какую-то операцию. Актор A может затем попросить актора B отказаться от выполнения этой операции. Но все эти просьбы выполняются асинхронно. Т.е. первая просьба от A к B идет в момент времени t0, но доходит до B только в какой-то последующий момент (t0+d0). Так же и со второй просьбой: А отсылает ее в t1, но дойдет она до B в (t1+d1).
1. Реализация проверки актуальности каждого сообщения перед его обработкой. Позволяет получить отзывные сообщения, но ценой увеличения стоимости обработки любого сообщения. На синтетических бенчмарках это может означать потерю 7-8% производительности. Меня лично такой вариант вполне устроит, но с точки зрения маркетинга такая потеря не есть гуд.
С точки зрения «не платить за то, что не используешь», может есть возможность сделать какую-то настройку для диспечера (параметр шаблона или ещё что-то такое)?Не думаю, что это хороший вариант. Опыт разработки диспетчеров показывает, что чем меньше диспетчер знает про детали вызова обработчика события, тем лучше. В идеале, если диспетчер вообще просто вызывает call_handler для execution_demand_t и все.
struct my_timer_message:
public so_5::lifetime_message_t
{
...
}
st.lifetime_event( &MyAgent::on_timer );
Имхо, это одна из вариаций на тему revocable_t
Т.е. прошлись по очереди, если встретили такой вид сообщений, проверили и удалили если устарело.Не во всех диспетчерах такое можно обеспечить. Даже среди тех, что уже есть. А если рассматривать диспетчеры, которые интегрируются с какими-то другими компонентами (например, очередью сообщений Windows, очередью событий в Qt, очередями в QNX и т.д.), то от диспетчеров вообще сложно требовать возможности «пробежаться по очереди».
Потенциально, есть еще один вариант, который заточен именно под работу с таймерными сообщениями. ..
А в целом отмена событий кажется мне очень сомнительной практикой, которая может скорее все запутать, чем помочь что-то решить.В общем, да, это не такая штука, которая должна использоваться повсеместно. Но бывают ситуации, когда агент A попросил агента B выполнить какую-то операцию, которая может занимать довольно много времени. Например, агент B проверяет рисковость платежа и этот агент единственный, тогда как агентов A несколько и запросы от A к B могут скапливаться в очереди. Пока B обрабатывает предыдущие запросы агент A может понять, что операцию проводить уже не нужно. Скажем, клиент сам отказался от платежа.
Легко ли добавлять новые фичи в старый фреймворк? Муки выбора на примере развития SObjectizer-а