2012-03-18 5 views
33

C++ 11 представляет новый способ завершения выполнения программы - std::quick_exit.В чем разница между std :: quick_exit и std :: abort и почему нужен std :: quick_exit?

Цитируя N3242 18.5 (стр 461).:

[[noreturn]] void quick_exit(int status) noexcept; 

эффекты: Функции, зарегистрированные вызовами at_quick_exit называются в обратном порядке их регистрации, за исключением того, что функция наречется после того, как ранее зарегистрированные функции, которые имели , уже были вызваны во время регистрации. Объекты не должны быть уничтожены в результате вызова . Если элемент управления оставляет зарегистрированную функцию, вызванную quick_exit, потому что функция не предоставляет обработчик для исключенного броска, terminate(). [Примечание: at_quick_exit может вызывать зарегистрированную функцию из другого потока , кроме зарегистрированного, поэтому зарегистрированные функции должны не полагаться на идентификатор объектов с продолжительностью хранения потоков. - конец примечания] После вызова зарегистрированных функций quick_exit должен позвонить _Exit(status). [Примечание: стандартные буферы файлов не очищаются. См .: ISO C 7.20.4.4. - конец примечание]

Поскольку определение std::abort(void) и std::_Exit(int status) отличается только способностью передавать статус родительского процесса, это поднимает мой вопрос.

Означает ли это, что единственное различие в семантике между std::quick_exit и std::abort том, что std::quick_exit вызовы функции регистрируются с помощью std::at_quick_exit и позволяет установить возвращаемый статус?

Каково было обоснование для введения этой функции?

ответ

34

Там хорошая рецензия available here, я просто резюмировать. Эта функция была добавлена, чтобы конкретно решить сложность окончательного завершения программы, когда вы используете потоки. По своей природе выход запускается очень асинхронным событием, пользователь закрывает пользовательский интерфейс, администратор отключает машину и т. Д. Это происходит независимо от состояния потоков, начатых программой, они почти всегда находятся в крайне непредсказуемом состоянии.

В идеальном мире функция main() программы просит, чтобы потоки выходили, как правило, сигнализируя о событии, ждет завершения потоков, а затем выходит из main() для чистого выключения через exit(). Однако этот идеал очень трудно достичь. Поток может быть похоронен глубоко внутри системного вызова, скажем, в ожидании завершения ввода/вывода. Или он блокирует объект синхронизации, который должен быть сигнализирован другим потоком в правильном порядке. Результат редко бывает приятным, реальные программы часто заходят в тупик при выходе. Или сбой при непредвиденном порядке выключения.

Простой и очень заманчивый обходной путь для этой проблемы: вместо этого вызовите _exit(). Kaboom, программа закончилась, операционная система впадает в шрапнель. Но явно без какой-либо очистки вообще, очень беспорядочно иногда с артефактами наподобие наполовину написанного файла или неполной транзакции dbase.

std :: quick_exit() предлагает альтернативу. Подобно _exit(), но с еще возможностью выполнить какой-то код, независимо от того, что было зарегистрировано в at_quick_exit.

+5

Кроме того, поскольку 'abort' сигнализирует' SIGABRT', вызов 'abort' будет обычно приводить (хотя это настраивается) в * * core dump ** on * nix или во всплывающем окне Windows (например, _Program перестала работать, Close/Debug_). Используйте только «abort» при завершении из-за ** неожиданного условия **, и вы хотите, чтобы coredump/minidump ** диагностировать причину ** для неожиданного состояния. – vladr

2

std::abort прекратит ваше приложение без каких-либо функций, зарегистрированных с помощью функции «at_exit/at_quick_exit». С другой стороны, std::quick_exit, как вы указали, вызовет функции, зарегистрированные с помощью std::at_quick_exit.

std::abort обычно прекращает свое приложение, это должно быть названо, когда некоторые ненормальная ситуация происходит, и ваше приложение должно быть закрыто без выполнения каких-либо ыборкы. Из std::abort документации:

Вызывает аварийное завершение программы, если SIGABRT не быть пойманной обработчик сигнала, передаваемый сигнал и обработчик не возвращает.

Если вы хотите выполнить некоторые очистки, std::quick_exit будет более подходящим. Эта последняя функция также позволяет вам прекратить ваше приложение изящно, так как оно заканчивается вызовом std::_Exit вместо того, чтобы сигнализировать сигнал, например std::abort (который сигнализирует SIGABRT, что делает приложение ненормальным).

std::exit позволяет вам изящно выйти из приложения, одновременно очищая автоматические, локальные и статические переменные потока. std::quick_exit нет.Вот почему в названии есть «quick_», это быстрее, так как он пропускает фазу очистки.

Таким образом, существует настоящая смысловая разница между обеими функциями. Один останавливает приложение ненормально, а другой выполняет изящный выход, что позволяет вам делать некоторые очистки.

+1

И это до сих пор не разрешено - зачем разрешать делать некоторые очистки и не все, когда прекращение делается «изящно»? Я никогда не видел «quick_exit» в реальном коде, но если бы я получил его в обзоре кода, я бы, наверное, захотел попросить сделать его полную очистку или ничего. Есть ли какие-либо источники в WG21 об этом? –

+0

Если вы хотите полную очистку, тогда вы будете использовать «выход». quick_exit быстрее, поскольку он не вызывает никаких автоматических, дескрипторов потоков локальных и статических переменных. Я считаю, что было бы лучше сравнить std :: quick_exit с std :: exit, так как оба они позволяют пользователю выполнять изящное закрытие, а std :: abort в основном прерывает ваше приложение ненормально. – mfontanini

+5

Деструкторы C++ обычно делают что-то (например, свободную память), которые не нужны, когда процесс выходит (потому что ОС это сделает). Я предполагаю, что 'quick_exit' позволяет вам выполнить некоторую очистку, но остальное остальное для ОС. –

19

Обоснование для std::quick_exit обсуждается в N1327 и N2440. Основные различия между quick_exit, _Exit и exit касается обработки статических деструкторов и промывки критической информации для стабильного хранения:

  • std::_Exit: не выполняют статические деструкторы или флеш-критический IO.
  • std::exit: выполняет статические деструкторы и сбрасывает критические значения ввода-вывода.
  • std::quick_exit: не выполняет статические деструкторы, но выполняет сброс критического ввода-вывода.

(Как уже упоминалось, std::abort просто посылает SIGABRT.)

+2

Я не вижу никаких доказательств в стандарте, что std :: quick_exit сбрасывает критический IO. Фактически, стандарт говорит «Примечание: стандартные буферы файлов не очищаются». В чем заключается ваша убежденность в том, что std :: quick_exit сбрасывает критический IO и, если на то пошло, что вы подразумеваете под «критическим» IO? – KnowItAllWannabe

+2

@KnowItAllWannabe: Он определяет критическое значение, поскольку «вы достаточно заботились об этом, чтобы зарегистрировать обработчик' at_quick_exit': –