SObjectizer
5.1
|
Обработка исключений в событиях агентов. so_5: Версия 5.1.0
В предыдущих версиях SObjectizer-а исключения в обработчиках событий не обрабатывались. Это мог делать сам пользователь внутри метода-обработчика события:
Недостатками при таком подходе является: - Накладные расходы на try-catch при выполнении обработчика. - Увеличение повторяющегося кода по обработке исключений. - При отсутствии блока try-catch в теле обработчика события, если выбрасывалось исключение, то это приводило к некорректному завершению работы программы. В v.5.0.0 обработчики событий могут выбрасывать исключения, с одним лишь требованием - выбрасываемое исключение должно быть наследником std::exception. В SObjectizer предусмотрен механизм позволяющий отлавливать исключения, в который можно встроить собственный обработчик и журнализатор исключения. Для этого вводится следующего понятия: - \ref so_5__5_1_0__event_exception__logger - объект, который выполняет действия необходимые для логирования возникшего исключения; - \ref so_5__5_1_0__event_exception__handler - объект, который определяет, какой должна быть реакция на возникшее исключение.
По умолчанию, стандартный журнализатор исключений печатает сообщение с описанием ошибки, которое возвращает \c std::exception::what() в \c std::cout. Для определения своего журнализатора необходимо реализовать интерфейс std_event_exception_logger_t.
Метод std_event_exception_logger_t::log_exception() служит для выполнения логирования и в него передается информация об исключении и кооперации агента, событие которого выбросило исключение. Метод so_5::rt::std_event_exception_logger_t::on_install() необходим для того, чтобы в ситуации, когда ставится новый журнализатор, объект, который станет новым журнализатором, сам решил, что делать со старым журнализатором, умный указатель на который передается ему при его установке. Достаточно реализовать метод только std_event_exception_logger_t::log_exception(), метод std_event_exception_logger_t::on_install(), по умолчанию, удаляет журнализатор-предшественник. Альтернативой может быть выстраивание журнализаторов в цепочку, когда, например, новый журнализатор забирает себе владение предшественником, и в методе логирования информации об исключении, вместе с выполнением собственного логирования, вызывает и логирование предшественником. Например, если необходимо добавить собственный слой логирования исключений и при этом не затрагивать правила логирования, которые были изначально, то можно написать следующим образом:
Рассмотрим другой пример. Пусть мы хотим отдельно фиксировать возникновение исключений для разных коопераций. Тогда код журнализатора может выглядеть так:
Для установки в SObjectizer нового журнализатора исключений служит функция so_environment_t::install_exception_logger(). Если впоследствии необходимо поставить стандартный журнализатор исключений, то его можно создать с помощью функции create_std_event_exception_logger(). Пример использования собственного журнализатора исключений \ref so_5/exception_logger
Для определения своего обработчика исключений необходимо реализовать интерфейс event_exception_handler_t.
При возникновении исключений может понадобиться дерегистрировать кооперацию агента, который вызвал исключение, инициировать завершение работы SObjectizer, отправить каким-либо агентам сообщение и т.д. и т.п. Получается, что при возникновении исключения может понадобиться выполнить большое количество операций, либо эти операции выполняются продолжительное время. А т.к. обращения к обработчику исключений происходят синхронно, то, чтобы не держать другие рабочие нити, на которых тоже могут возникнуть исключения, на общем мутексе, решено передать ответственность за выполнение реакции на возникшее исключение отдельному объекту с интерфейсом event_exception_response_action_t. Задача обработчика заключается в создании подходящего объекта ответного действия, которое инициализируется методом event_exception_response_action_t::respond_to_exception(). Этот метод определяет, как надо реагировать на возникшее исключение. Т.о. event_exception_handler_t является фабрикой для объектов-реакций на возникшее исключение, которая в зависимости от типа возникшего исключения (через dynamic_cast можно уточнять, не является ли исключение исключением заданного класса) или/и от сообщения об ошибке, агента конкретной кооперации, решает, какой должна быть реакция, после чего создает объект соответствующий заданной реакции и возвращает умный указатель на созданный объект. Метод event_exception_handler_t::on_install(), по умолчанию удаляет обработчик-предшественник. Альтернативный подход - выстраивание обработчиков в цепочку, в которой обработчик обращается к предшественнику в случае, если сам не может определить, какой должна быть реакция на возникшее исключение при имеющейся информации об исключении. Рассмотрим пример. Пусть у нас есть несколько типов исключений, и на каждое из них предусмотрена отдельная реакция. Будем выстраивать их в цепочку. Каждый обработчик будет проверять не является ли исключение исключением заданного типа, и если является, то обработчик возвращает определенный для данного исключения объект-ответчик:
Аналогично поступаем и с обработчиками для других исключений:
base_exception_t
, не проверял бы его раньше, чем обработчик, который проверяет, не является ли исключение типом derived_exception_t
, который унаследован от base_exception_t
. Т.е. действуют привила для последовательности типов в конструкциях catch
.Для установки в SObjectizer нового обработчика исключений служит функция so_environment_t::install_exception_handler(). Если впоследствии необходимо поставить стандартный обработчик исключений, то его можно создать с помощью функции create_std_event_exception_handler().
Пример использования собственного обработчика исключений sample/so_5/exception_handler/main.cpp
Документация по SObjectizer v.5.1 'Джимара'. Последние изменения: Ср 15 Май 2013 12:56:21. Создано системой 1.8.3.1 |