В чем разница между использованием _exit () и exit () в обычном Linux-fork-exec? - PullRequest
46 голосов
/ 24 марта 2011

Я пытался выяснить, как механизм fork-exec используется в Linux. Все шло по плану, пока некоторые веб-страницы не начали меня смущать.

Говорят, что дочерний процесс должен строго использовать _exit() вместо простого exit() или обычного возврата из main().

Как я знаю, оболочка Linux выполняет каждую из внешних команд; предполагая, что сказанное выше верно, можно сделать вывод, что ни одна из этих внешних команд, ни какое-либо другое выполнение, происходящее внутри оболочки Linux, не может выполнить нормальный возврат!

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

Я провел весь день на этом ... Спасибо за любые разъяснения.

Ответы [ 4 ]

43 голосов
/ 24 марта 2011

Вы должны использовать _exit (или его синоним _Exit), чтобы прервать дочернюю программу в случае сбоя exec, потому что в этой ситуации дочерний процесс может мешать родительскому процессу ' внешние данные (файлы), вызывая их atexit обработчики, вызывая их обработчики сигналов и / или очищая буферы.

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

Во всех остальных случаях просто используйте exit. Как вы частично заметили, каждый процесс в Unix / Linux (кроме одного, init) является дочерним по отношению к другому процессу, поэтому использование _exit в каждом дочернем процессе будет означать, что exit бесполезен за пределами init.

switch (fork()) {
  case 0:
    // we're the child
    execlp("some", "program", NULL);
    _exit(1);  // <-- HERE
  case -1:
    // error, no fork done ...
  default:
    // we're the parent ...
}
16 голосов
/ 14 февраля 2014

exit() очищает буферы ввода-вывода и выполняет некоторые другие функции, такие как запуск функций, зарегистрированных atexit().exit() вызывает _end( )

_exit() просто завершает процесс без этого.Например, вы вызываете _exit() из родительского процесса при создании демона.

Когда-нибудь замечали, что main() - это функция?Вы никогда не задумывались, как это называется?Когда программа ac запускает оболочку, в которой вы запускаете, предоставляет путь к исполняемому файлу для системного вызова 'exec', и управление передается ядру, которое, в свою очередь, вызывает функцию запуска каждого исполняемого файла _start(), вызывает ваш main(), когда main() возвращает его, затем вызывает _end() В некоторых реализациях C используются немного разные имена для _end() & _start() ...

exit() и _exit() invoke _end()

Обычно - для каждого main() должен быть один и только один exit() звонок.(или возврат в конце main())

2 голосов
/ 25 марта 2017

exit () находится в верхней части _exit (), используя обычную библиотеку C.

Есть различия:

  1. _exit () не сбрасывает буфер stdio, а exit () очищает буфер stdio перед выходом.

  2. _exit () не может выполнить процесс очистки, в то время как exit () может быть зарегистрирован с помощью некоторой функции (например, on_exit или at_exit) для выполнения некоторого процесса очистки, если все, что требуется перед существованием программы.

exit (status) просто передает статус выхода в _exit (status). Рекомендуется всякий раз, когда выполнять fork (), один из них между дочерним и родительским, один использовать _exit (), а другой использовать exit ().

0 голосов
/ 08 февраля 2019

В дочерней ветви fork() обычно неправильно использовать exit(), поскольку это может привести к сбросу буферов stdio дважды и неожиданному удалению временных файлов.

Выдержка из: http://www.unixguide.net/unix/programming/1.1.3.shtml

...