Процессы, сигналы и задания оболочки
Вы запустили локальный сервер, и терминал больше не показывает приглашение. В другом окне порт занят. Кажется, что компьютер завис, но скорее всего работает обычный процесс. Нужно найти именно своё исполнение и решить, ждать его, приостановить или корректно завершить.
Во второй главе процесс получил PID и пользователя. Теперь проследим жизненный цикл. Все сигналы направляем только дочерним процессам, которые сами создаём в опыте. Не используйте массовый killall или поиск с последующим уничтожением чужих процессов. Практика займёт около двадцати минут.
Передний и задний план
Shell обычно ждёт завершения команды переднего плана. Пока выполняется sleep 10, десять секунд не возвращается приглашение. Это не означает, что sleep загружает процессор: он ждёт. CPU, память и ожидание ввода-вывода — разные состояния работы.
sleep 30 &
child_pid=$!
printf 'child=%s\n' "$child_pid"
jobs
ps -p "$child_pid" -o pid,ppid,stat,commСимвол & запускает команду без обычного ожидания. $! получает PID последнего фонового запуска; сохраните его сразу. jobs показывает задания этой интерактивной оболочки, а ps — процессы системы. Номер задания вроде [1] и системный PID не одно число. Другая оболочка не обязана иметь тот же список jobs.
Столбец STAT показывает состояние в обозначениях конкретного ps. Сон часто обозначается S, остановка — T. Вывод зависит от момента наблюдения; процесс может закончиться между командами. Нельзя считать отсутствие строки свидетельством, что команда никогда не выполнялась.
Сигнал — запрос процессу
Сигнал сообщает процессу о событии. SIGTERM обычно просит завершиться; программа может обработать его и успеть закрыть ресурсы. SIGKILL не даёт выполнить пользовательский обработчик. Он полезен как крайняя мера, но лишает приложение возможности сохранить незавершённую работу. Сигнал сам по себе не откатывает внешние эффекты.
kill -TERM "$child_pid"
wait "$child_pid"
status=$?
printf 'child exit=%s\n' "$status"Мы обращаемся к своему sleep. wait забирает результат дочернего процесса и завершает ожидание; ненулевой код после сигнала ожидаем. В Bash для завершения сигналом часто используется 128 плюс номер сигнала, но переносимая программа не должна угадывать всю причину по одному такому числу. Подробности задаёт договор shell.
Если процесс уже завершился, kill может сообщить об отсутствии такого PID. Не повторяйте позже сохранённый PID без проверки: система способна переиспользовать номера. Для упражнений создание, наблюдение и завершение идут в одном коротком сеансе. У сервиса менеджер хранит более устойчивую связь с его запуском.
Ctrl+C, Ctrl+Z и продолжение
Ctrl+C обычно приводит к SIGINT для группы процессов переднего плана. Приложение может завершиться либо обработать сигнал. Ctrl+Z обычно останавливает переднюю группу через SIGTSTP; это не окончание работы и не освобождение всех ресурсов. Настройки терминала и программы могут изменить поведение.
Запустите sleep 60 в интерактивном Bash, нажмите Ctrl+Z, затем jobs. Команда fg вернёт задание на передний план. После этого Ctrl+C завершит ваш sleep. bg продолжает остановленное задание в фоне. Не оставляйте учебные задания забытыми: они могут удерживать файлы или порт, даже если приглашение вернулось.
Пользовательский терминал, группа процессов и отдельный PID — разные границы. Поэтому pipeline может получать сигнал как группа, а завершение одного элемента не обязательно останавливает остальных автоматически. Не делайте из фонового запуска обещание, что приложение переживёт выход или перезагрузку.
Родитель должен узнать результат
Завершившийся процесс оставляет минимальные сведения для родителя, пока тот не заберёт статус. Такое состояние называют zombie. Оно отличается от активно работающего процесса: kill не восстановит уже закончившееся исполнение. Потеря родителя тоже не делает каждый процесс немедленно завершённым; система принимает дальнейшее управление по своей модели.
Для разработчика практический вывод проще терминов: запускающий код должен учитывать статус и освобождение ресурсов. В shell используйте wait для своих фоновых работ; для долгого сервиса позже выберем systemd. Команда nohup может изменить обработку отключения терминала, но она не заменяет автозапуск, журналирование и наблюдение службы.
Чтобы найти нагрузку, начните с ps, затем интерактивного top, если он установлен. Нажатие q обычно выходит. Проценты CPU показывают наблюдаемый интервал и могут иметь особенности многопроцессорной системы. Высокое использование памяти не всегда равно утечке: нужно наблюдать рост, тип памяти и реальные ограничения.
Самостоятельная лаборатория
Запустите свой sleep в фоне, запишите PID и PPID, найдите его в jobs и ps, завершите SIGTERM и заберите результат через wait. Во втором опыте приостановите передний sleep и продолжите через fg. Запишите, когда возвращалось приглашение и что изменилось в состоянии.
Критерии готовности: вы действуете по сохранённому PID собственного ребёнка, отличаете остановку от завершения, не называете возвращение приглашения доказательством смерти процесса. После опытов jobs не должен показывать работающий учебный sleep. Если команда завершилась естественно, это тоже нужно отметить.
Разбор
Фоновый процесс освобождает shell от ожидания, но продолжает существовать. TERM передаёт запрос, wait получает итог. Ctrl+Z сохраняет остановленное исполнение, fg продолжает его в терминале. Для сервера эти различия объясняют занятый порт и необходимость корректного выключения. Прежде чем запускать полноценные инструменты, разберём установку пакетов и их происхождение.
Первичные источники: Linux signals, GNU Bash: job control, Bash wait.