Подтвердить что ты не робот

В чем разница между использованием _exit() & exit() в обычном Linux fork-exec?

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

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

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

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

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

4b9b3361

Ответ 1

Вы должны использовать _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 ...
}

Ответ 2

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

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

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

exit() и _exit() invoke _end()

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

Ответ 3

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

Существуют различия:

  • _exit() не будет удалять буфер stdio, а exit() удаляет буфер stdio до выхода.

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

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