Исключения все еще нежелательны в среде реального времени? - PullRequest
41 голосов
/ 10 марта 2011

Пару лет назад меня учили, что в приложениях реального времени , таких как встроенные системы или (не-Linux-) разработка ядра C ++ - исключения , нежелательны. (Может быть, этот урок был до gcc-2.95). Но я также знаю, что обработка исключений стала лучше.

Таким образом, C ++ - исключения в контексте приложений реального времени на практике

  • совершенно нежелателен?
  • даже быть выключенным через компилятор-переключатель?
  • или очень осторожно в использовании?
  • или теперь так хорошо справляются, что их можно использовать почти свободно, имея в виду несколько вещей?
  • Изменяет ли C ++ 11 что-либо w.r.t. это?

Обновление : Требуется ли для обработки исключений RTTI (как предложил один из ответчиков)? Есть ли динамическое приведение или подобное?

Ответы [ 8 ]

22 голосов
/ 10 марта 2011

Исключения теперь хорошо обрабатываются, и стратегии, используемые для их реализации, фактически делают их быстрее, чем тестирование кода возврата, потому что их стоимость (с точки зрения скорости) практически равна нулю, если вы их не выбрасываете.

Однако они стоят: в размере кода.Исключения обычно работают рука об руку с RTTI, и, к сожалению, RTTI отличается от любой другой функции C ++ тем, что вы либо активируете, либо деактивируете ее для всего проекта, и после активации она сгенерирует дополнительный код для любого класса, в котором есть виртуальный метод.таким образом, бросая вызов «вы не платите за то, что не используете мышление».

Кроме того, для его обработки требуется дополнительный код.

Поэтому стоимость исключений должна бытьизмеряется не с точки зрения скорости, а с точки зрения роста кода.

РЕДАКТИРОВАТЬ :

С @Space_C0wb0y: эта статья блога даетнебольшой обзор и представляет два широко распространенных метода для реализации исключений Jumps и Zero-Cost .Как следует из названия, хорошие компиляторы теперь используют механизм Zero-Cost .

В статье Википедии об обработке исключений рассказывается об используемых двух механизмах .Механизм Zero-Cost - это Table-Driven one.

EDIT :

От @Vlad Lazarenko, чей блогЯ упоминал выше, что наличие исключительной ситуации может помешать компилятору встроить и оптимизировать код в регистрах.

11 голосов
/ 10 марта 2011

Ответ только на обновление:

Действительно ли для обработки исключений требуется включение RTTI

Для обработки исключений на самом деле требуется нечто более мощное, чем RTTI и динамическое приведениеодно уважение.Рассмотрим следующий код:

try {
    some_function_in_another_TU();
} catch (const int &i) {
} catch (const std::logic_error &e) {}

Итак, когда функция в другом TU сгенерирует, она будет искать стек (либо сразу проверять все уровни, либо проверять один уровень за раз во время разматывания стека,это до реализации) для предложения catch, которое соответствует выбрасываемому объекту.

Для выполнения этого соответствия может не потребоваться аспект RTTI, который хранит тип в каждом объекте, так как тип брошенногоИсключением является статический тип выражения броска.Но ему нужно сравнивать типы instanceof и делать это во время выполнения, потому что some_function_in_another_TU можно вызывать откуда угодно, с любым типом перехвата в стеке.В отличие от dynamic_cast, он должен выполнять эту проверку экземпляра во время выполнения для типов, которые не имеют виртуальных функций-членов, и в этом случае для типов, которые не являются типами классов.Последняя часть не добавляет трудностей, потому что не относящиеся к классам типы не имеют иерархии, и поэтому все, что нужно, это равенство типов, но вам все равно нужны идентификаторы типов, которые можно сравнивать во время выполнения.

Итак, если выВключите исключения, тогда вам нужна часть RTTI, которая выполняет сравнения типов, например, dynamic_cast, но охватывает больше типов.Вам не обязательно нужна та часть RTTI, которая хранит данные, используемые для выполнения этого сравнения, в vtable каждого класса, где она достижима из объекта - вместо этого данные можно кодировать только в точке каждого выражения throw и каждого предложения catch,Но я сомневаюсь, что это значительная экономия, поскольку typeid объекты не совсем массивны, они содержат имя, которое в любом случае часто требуется в таблице символов, а также некоторые данные, определенные реализацией для описания иерархии типов.Так что, вероятно, к этому моменту вы могли бы иметь все RTTI.

8 голосов
/ 10 марта 2011

Проблема с исключениями - не обязательно скорость (которая может сильно различаться в зависимости от реализации), а то, что они на самом деле делают.

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

Если вы имеете в виду «в реальном времени» как фактически «встроенный», то размер кода, как уже упоминалось, становится проблемой. Встроенный код не обязательно может быть в реальном времени, но он может иметь ограничение по размеру (и часто имеет).

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

Так лучше, чем потом сожалеть: не используйте исключения. Если вы можете выдержать случайные сбои системы, если вы выполняете отдельное задание, которое может быть легко перезапущено, если вы не работаете в режиме реального времени, просто притворитесь - тогда вы, вероятно, можете попробовать. Если вы пишете программное обеспечение для кардиостимулятора - я бы предпочел проверить коды возврата.

5 голосов
/ 10 марта 2011

Исключения C ++ до сих пор не поддерживаются каждой средой реального времени, что делает их приемлемыми везде.

В конкретном примере видеоигр (с мягким крайним сроком 16,6 мс для каждого кадра) ведущие компиляторы реализуют исключения C ++ таким образом, что простое включение обработки исключений в вашей программе значительно замедлит их и увеличит код размер, независимо от того, действительно ли вы бросаете исключения или нет Учитывая, что производительность и память являются критически важными для игровой приставки, это является решающим фактором: например, блоки SPU PS3 имеют 256 КБ памяти для кода и данных!

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

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

3 голосов
/ 10 марта 2011

Реализация механизма исключений обычно очень медленная, когда выдается исключение, в противном случае затраты на их использование практически отсутствуют.На мой взгляд, исключения очень полезны, если вы используете их правильно.

В приложениях RT исключения должны создаваться только тогда, когда что-то идет не так, и программа должна остановиться и исправить проблему (и, возможно, дождаться взаимодействия с пользователем).).При таких обстоятельствах для устранения проблемы требуется больше времени.

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

1 голос
/ 20 ноября 2014

Типичные реализации обработки исключений в C ++ по-прежнему не идеальны и могут привести к тому, что полная языковая реализация станет практически непригодной для некоторых встроенных целей с чрезвычайно ограниченными ресурсами, даже если пользовательский код явно не использует эти функции.Это упоминается как «нарушение принципа нулевых накладных расходов» в последних работах WG21, подробности см. N4049 и N4234 .В таких средах обработка исключений не работает должным образом (потребляя разумные системные ресурсы), независимо от того, работает приложение в реальном времени или нет.

Однако во встроенных средах должны быть приложения реального времени, которые могут позволить себе эти издержкиНапример, видеопроигрыватель в портативном устройстве.

Обработка исключений всегда должна выполняться осторожно.Создание и перехват исключений для каждого кадра в приложении реального времени для любых платформ (не только для встроенных сред) является плохим проектом / реализацией и в целом неприемлемым.

0 голосов
/ 10 марта 2011

Во встроенной / реальной разработке обычно есть 3 или 4 ограничения, особенно когда это подразумевает разработку в режиме ядра

  • в различных точках - обычно при обработке аппаратных исключений - операции НЕ ДОЛЖНЫ генерировать больше аппаратных исключений. Неявные структуры данных (vtables) и код в c ++ (конструкторы и операторы по умолчанию и другой неявно сгенерированный код для поддержки механизма исключений c ++) не размещаются и в результате не могут быть гарантированно помещены в невыгружаемую память при выполнении в этом контексте.

  • Качество кода - код c ++ в целом может скрывать много сложностей в операторах, которые выглядят тривиально, что затрудняет визуальный аудит кода на наличие ошибок. исключения исключают обработку из местоположения, затрудняя проверку кода тестами.

  • C ++ предоставляет очень простую модель памяти: new выделяет из бесконечного свободного хранилища до тех пор, пока вы не исчерпаете, и выдает исключение. В устройствах с ограниченным объемом памяти может быть написан более эффективный код, который явно использует блоки памяти фиксированного размера. Неявное распределение C + практически для любой операции делает невозможным аудит использования памяти. Кроме того, большинство кучи c ++ проявляют тревожное свойство: отсутствует вычисляемый верхний предел того, сколько времени может занять выделение памяти, что опять же затрудняет доказательство времени отклика алгоритмов на устройствах реального времени, где желательны фиксированные верхние пределы.

0 голосов
/ 10 марта 2011

Есть еще один недостаток исключений.

Исключения обычно хорошо и легко обрабатываются в языках с автоматическим управлением памятью (например, C #, python и т. Д.)

Но в C ++, где большую часть времени приходится контролировать выделение памяти и освобождение объектов(новый и удалить), во многих ситуациях исключения стали очень хитрыми.Когда исключение случается часто, нужно освободить ресурсы, выделенные ранее.И в некоторых случаях сложно выбрать подходящий момент и место для него.И такие вещи, как авто указатели могут спасти вас только в некоторых случаях.

Утечки памяти, ошибки или непредсказуемые действия могут быть результатом неправильной обработки объектов / памяти во время исключений в C ++.Это приводит к медленной разработке и отладке действительно сложных ошибок.

...