PDA

Просмотр полной версии : Механизм TRY_CATCH в CODESYS V3



Спорягин Кирилл
06.02.2026, 17:44
Доброго времени суток, уважаемые форумчане.

Прошу поделиться своим опытом использования механизма TRY_CATCH (операторы __TRY, __CATCH) в CODESYS V3.

Почему заинтересовался этим вопросом?
За уже почти 20 лет работы программистом в области АСУ ТП, еще их не использовал ни разу в реальных проектах.
С другой стороны механизм реализован в CODESYS. Механизм призван повысить надежность программного кода, т.е. в том месте, где при ошибке программиста будет WatchDog или останов программы по исключению, при его использовании должно все продолжать работать, а в логах будет сообщение об ошибке.

Материала по данной теме для стандарта МЭК 61131-3 довольно мало. Вот что нашел и прочел:
1. Справка CODESYS
2. Статья Стефана Хеннекена: https://stefanhenneken.net/2019/07/29/iec-61131-3-exception-handling-with-__try-__catch/
3. Статьи для других языков

Везде объясняется синтаксис и базовые способы использования. Нигде нет толковых примеров, которые давали бы понять в какой момент нужно использовать TRY_CATCH, а где это не нужно, избыточно. Не использовать же __TRY для вызова любой функции/ФБ?

Вот пару собственных соображений/размышлений на этот счет:
1. Классический пример деления на ноль. Попробовал. Да, работает, в журнале вижу сообщение о таком исключении. Но я всегда просто проверял знаменатель на "не равен нулю".
В чем тут принципиальная разница мне не ясно!
2. Работал с библиотекой "CAA Net Base Services". Библиотека содержит ФБ для работы с сокетами. В частности блок TCP_Client открывает сокет и устанавливает соединение с удаленным сервером. Возвращает указатель на соединение (hConnection), который нужно передавать в блоки TCP_Write и TCP_Read. Решил попробовать, в секции __TRY вызвать TCP_Write и передать на вход нулевой указатель. В результате блок TCP_Write выдал на своем выходе ошибку 6003, а в секцию __CATCH не попадал, т.е. ошибка обработана внутри блока TCP_Write (что логично).
Получается, что использование для вызова блока TCP_Write/TCP_read механизма TRY_CATCH не нужно!
3. Наткнулся на ситуацию, когда при использовании __TRY все равно система зависла, хотя в журнале видно, что механизм отработал и мы попадали в секцию CATCH: https://owen.ru/forum/showthread.php?t=41771&p=479534#post479534


Буду благодарен за советы и соображения!
Спасибо!

Евгений Кислов
06.02.2026, 18:43
Добрый день.


при его использовании должно все продолжать работать

Должно кому? В том смысле - кто это вам обещал?

Спорягин Кирилл
09.02.2026, 12:19
Должно кому? В том смысле - кто это вам обещал?

В справке CODESYS V3 моя мысль выражена фразой: "...приложение выполняет последующие операторы".
87965

Евгений, Вы же понимаете, что вопрос не об этом?

Спорягин Кирилл
09.02.2026, 12:30
Но, я еще раз поясню суть вопроса.

Пока я вижу ситуацию так.
В каких-то случаях (пример №1 из первого поста) использование не нужно, так как можно и без механизма TRY/CATCH выполнить программу так, что не будет исключения при выполнении. Или другими словами, если человек не чувствует, что нужно проверить знаменатель на не равенство нулю, то он и механизм TRY/CATCH не решит использовать в этой ситуации.
В других случаях (пример №2) использование излишне, так как разработчик используемого ФБ уже корректно обработал исключения внутри своих блоков и при их использовании не поймать исключение.
И, наконец, если разработчик системного блока совершил ошибку (пример №3), то программа все равно упадет. Подозреваю, что в рассмотренном примере происходит порча памяти где-то внутри CODESYS. Поэтому в момент, когда мой оператор совершает некорректное действие в операторе TRY система не падает, но потом, при первом же обращении к системному журналу уже других служб, происходит падение. Т.е. не от моей программы непосредственно, а "системно". Тут стоит заметить, что в журнале все же останутся какие-то следы, т.е. что вот попадали в секцию CATCH до этого. Т.е. будет над чем поразмышлять. Поэтому для 3го примера все равно следует признать, что есть смысл использовать этот механизм!

Поэтому и интересует опыт использования механизма TRY/CATCH.
Вероятно, приведенные мною примеры скудны и не отражают всю глубину механизма.
Буду рад, если другие приведут примеры использования, когда он, действительно, целесообразен.
И, конечно, хотелось бы понять критерий для рационального использования.

Спасибо.

Евгений Кислов
09.02.2026, 13:09
В справке CODESYS V3 моя мысль выражена фразой: "...приложение выполняет последующие операторы".
87965

Евгений, Вы же понимаете, что вопрос не об этом?

В справке указано, что если удалось выйти из оператора - то продолжат выполняться строки кода, размещенные после __END_TRY.
Это, на мой взгляд, и так очевидно.

Но это не равно формулировке "при его (__TRY) использовании должно все продолжать работать".

Во-первых, исключение может быть просто не детектировано. Вы как раз это наблюдаете в экспериментах с CMRemoveComponent.

Во-вторых, в реальном мире исключения в программе ПЛК, как показывает мой опыт, это обычно RTSEXCPT_ACCESS_VIOLATION или что-то аналогичное.
"Обработать" их в __CATCH не получится - память уже испорчена.
Максимум - можно попытаться освободить ресурсы (например, закрыть файл) - но и тут вам никто не даст гарантии, что это пройдет успешно.
Сообщение в лог в этом случае CODESYS выведет.


Поэтому для 3го примера все равно следует признать, что есть смысл использовать этот механизм!

Или можно просто добавить проверку на то, что удаляемый компонент действительно имеет смысл удалять.


так как разработчик используемого ФБ уже корректно обработал исключения внутри своих блоков]

И, скорее всего, сделал это без __TRY - а обычным сравнением указателя/размера буфера/дескриптора с нулем и т. п.

***
С вашем мнением по ситуациям с примерами 1 и 2 - согласен.

capzap
09.02.2026, 13:13
по мимо обработки ошибок можно внутри блока самому вызвать исключение, так по крайней мере в других ЯП, что например полезно при отладке знать по логам в какое время какой этап программы прошли, будет похоже на механизм точек останова, только без останова

Евгений Кислов
09.02.2026, 13:26
например полезно при отладке знать по логам в какое время какой этап программы прошли

В подобных ситуациях можно просто вывести сообщение в лог - с помощью библиотеки CmpLog.

Спорягин Кирилл
19.02.2026, 11:38
Товарищи!
Просмотрели тему (на 19.02.2026) 353 раза, а проголосовало всего 7 человек!

Понятно, что такие вопросы голосованиями не решаются, но все же было бы интересно понять статистику!

Dmnd
20.02.2026, 00:17
Навскидку предположу что с этими операторами в каком-то смысле улучшается читаемость кода. То есть сходу понятно, что вот тут есть риск свалиться в исключение, и конкретно вот этот кусок кода направлен на предотвращение.
Также предположу что это может быть удобно если есть какой-то исключительно проблемный кусок кода, и вместо кучи длинных и вложенных условий можно десять раз прописать __catch на разные типы исключений, и отдельно на случай если ни разу не угадал.

Cs-Cs
20.02.2026, 09:15
Спорягин Кирилл Я не могу придумать, для чего они будут нужны... Вот пытаюсь:
* Выход за границы памяти?
Но так в CodeSys есть CheckBounds (это раз). А ещё исключение может не возникать, когда ты просто "наехал" на соседнюю переменную (это два).
И проще писать код, задавая размеры массивов, буферов и итерации циклов их обхода через константы.
* Работа с портами и даже файлами?
Но так все такие функции возвращают коды ошибок, а не исключения. И по кодам ошибок можно понять, что делать дальше.
* Написать код, как на WinAPI было (когда в CATCH пишется закрытие всяких дескрипторов и прочее такое, чтобы попадать туда после любой ошибки в коде и корректно освобождать память)? Нууу... вот вроде да. По идее можно.
НО у нас же программа ПЛК крутится в цикле, и чаще всего вообще такая работа с объектами (открыть порт-файл, что-то сделать, закрыть) вообще делается на автомате состояний через CASE и занимает несколько циклов. И там проще сделать обработку ошибок через одно из состояний Автомата, чтобы не нарушать его логику...