Убивает ли linux фоновые процессы, если мы закрываем терминал, с которого он запущен?
У меня есть встроенная система, на которой я делаю telnet
и затем я запускаю приложение в фоновом режиме:
./app_name &
Теперь, если я закрою свой терминал и сделаю telnet
с другого терминала, и если я проверю, то я вижу, что этот процесс все еще работает.
Чтобы проверить это, я написал небольшую программу:
#include<stdio.h>
main()
{
while(1);
}
Я запустил эту программу на локальном компьютере с Linux в фоновом режиме и закрыл терминал.
Теперь, когда я проверил этот процесс с другого терминала, я обнаружил, что этот процесс также был убит.
Мой вопрос:
- Почему неопределенное поведение для процесса того же типа?
- От чего это зависит?
- Это зависит от версии Linux?
5 ответов
Кто должен убивать рабочие места?
Как правило, передние и фоновые задания убиваются SIGHUP
отправлено ядром или оболочкой при разных обстоятельствах.
Когда ядро отправляет SIGHUP
?
Ядро отправляет SIGHUP
контролировать процесс:
- для реального (аппаратного) терминала: при обнаружении разъединения в драйвере терминала, например, при зависании на модемной линии;
- для псевдотерминала (pty): когда последний дескриптор, ссылающийся на главную сторону pty, закрыт, например, когда вы закрываете окно терминала.
Ядро отправляет SIGHUP
другим группам процессов:
- на передний план группы процессов, когда управление процессом прекращается;
- к группе потерянных процессов, когда она становится осиротевшей и останавливает участников.
Процесс управления - это лидер сеанса, который установил соединение с управляющим терминалом.
Как правило, контролирующим процессом является ваша оболочка. Итак, подведем итог:
- ядро отправляет
SIGHUP
в оболочку, когда реальный или псевдотерминал отключен / закрыт; - ядро отправляет
SIGHUP
на передний план группы процессов при завершении оболочки; - ядро отправляет
SIGHUP
потерянной группе процессов, если она содержит остановленные процессы.
Обратите внимание, что ядро не отправляет SIGHUP
в группу фоновых процессов, если она не содержит остановленных процессов.
Когда делает bash
Отправить SIGHUP
?
Баш отправляет SIGHUP
на все рабочие места (передний план и фон):
- когда он получит
SIGHUP
и это интерактивная оболочка (и поддержка управления заданиями включена во время компиляции); - когда он выходит, это интерактивная оболочка входа в систему, и
huponexit
опция установлена (и поддержка управления заданиями включена во время компиляции).
Смотрите подробности здесь.
Заметки:
bash
не отправляетSIGHUP
на рабочие места, удаленные из списка работ с помощьюdisown
;- процессы начали использовать
nohup
игнорироватьSIGHUP
,
Подробнее здесь.
А как насчет других оболочек?
Обычно снаряды размножаются SIGHUP
, порождающий SIGHUP
при нормальном выходе встречается реже.
Telnet или SSH
Под telnet или SSH, следующее должно происходить, когда соединение закрыто (например, когда вы закрываете telnet
окно на ПК):
- клиент убит;
- сервер обнаруживает, что клиентское соединение закрыто;
- сервер закрывает главную сторону pty;
- ядро обнаруживает, что мастер pty закрыт и отправляет
SIGHUP
вbash
; bash
получаетSIGHUP
, отправляетSIGHUP
на все рабочие места и прекращается;- каждая работа получает
SIGHUP
и заканчивается.
проблема
Я могу воспроизвести вашу проблему, используя bash
а также telnetd
от busybox
или же dropbear
SSH сервер: иногда фоновое задание не получает SIGHUP
(и не прекращается), когда клиентское соединение закрыто.
Кажется, что гонка возникает, когда сервер (telnetd
или же dropbear
) закрывает главную сторону pty:
- обычно,
bash
получаетSIGHUP
и немедленно убивает фоновые задания (как и ожидалось) и прекращает работу; - но иногда,
bash
детектируетEOF
на подчиненной стороне Pty перед обработкойSIGHUP
,
когда bash
детектирует EOF
, он по умолчанию завершается немедленно без отправки SIGHUP
, И фоновая работа продолжается!
Решение
Можно настроить bash
отправлять SIGHUP
на нормальном выходе (в том числе EOF
) тоже:
Убедиться, что
bash
запускается как оболочка входаhuponexit
работает только для логинов, AFAIK.Оболочка входа включена
-l
вариант или ведущий дефис вargv[0]
, Вы можете настроитьtelnetd
бежать/bin/bash -l
или лучше/bin/login
который вызывает/bin/sh
в режиме входа в систему.Например:
telnetd -l / bin / login
включить
huponexit
вариант.Например:
шоп-хупонексит
Введите это в
bash
сеанс каждый раз или добавить его в.bashrc
или же/etc/profile
,
Почему происходит гонка?
bash
разблокирует сигналы только тогда, когда это безопасно, и блокирует их, когда какой-то фрагмент кода не может быть безопасно прерван обработчиком сигнала.
Такие критические секции время от времени вызывают точки прерывания, и, если сигнал получен при выполнении критической секции, его обработчик задерживается до тех пор, пока не произойдет следующая точка прерывания или не выйдет критическая секция.
Вы можете начать копать с quit.h
в исходном коде.
Таким образом, кажется, что в нашем случае bash
иногда получает SIGHUP
когда это в критическом разделе. SIGHUP
выполнение обработчика задерживается, и bash
читает EOF
и завершается перед выходом из критической секции или вызовом следующей точки прерывания.
Ссылка
- Раздел "Контроль работы" в официальном руководстве Glibc.
- Глава 34 "Группы процессов, сеансы и управление заданиями" книги "Интерфейс программирования Linux".
Когда вы закрываете терминал, оболочка отправляет SIGHUP
ко всем фоновым процессам - и это убивает их. Это может быть подавлено несколькими способами, в частности:
поЬир
Когда вы запускаете программу с nohup
это ловит SIGHUP
и перенаправить вывод программы.
$ nohup app &
отрекаться
disown
говорит оболочке не отправлять SIGHUP
$ app &
$ disown
Это зависит от версии Linux?
Это зависит от вашей оболочки. Выше относится по крайней мере для Баш.
AFAIK в обоих случаях процесс должен быть убит. Чтобы избежать этого, вы должны выполнить nohup, как показано ниже:
> nohup ./my_app &
Таким образом, ваш процесс будет продолжаться. Вероятно, часть telnet связана с ошибкой, подобной этой:
Для того, чтобы полностью понять, что происходит, вам нужно попасть в unix
внутренности немного.
Когда вы запускаете такую команду
./app_name &
app_name
отправляется в группу фоновых процессов. Вы можете проверить о unix
группы процессов здесь
Когда вы закрываете bash
при нормальном выходе это вызывает SIGHUP
сигнал зависания на все свои рабочие места. Некоторая информация о unix
контроль работы здесь.
Чтобы ваше приложение работало при выходе bash
вам нужно сделать ваше приложение невосприимчивым к сигналу зависания nohup
полезность.
nohup - запустить команду, защищенную от зависаний, с выводом не-tty
И, наконец, вот как вам нужно это сделать.
nohup app_name & 2> /dev/null;
В современном Linux, то есть в Linux с systemd, есть еще одна причина, по которой это может произойти, о которой вы должны знать: «задержка».
Если вы запустите
loginctl enable-linger $USER
вы можете отключить это поведение, позволяя фоновым процессам продолжать работать. Однако механизмы, охватываемые другими ответами, по-прежнему применяются, и вы также должны защитить свой процесс от них.
ls /var/lib/systemd/linger
Это могут быть файлы, по одному на имя пользователя, для пользователей, у которых есть enable-linger. Любой пользователь, указанный в каталоге, может оставить фоновые процессы запущенными при выходе из системы.