img

Как работают сигналы Linux: SIGINT, SIGTERM и SIGKILL

 

 

В системах Linux и Unix программные прерывания осуществляются черед сигналы. Существует достаточно большое количество различных сигналов Linux, но есть несколько, которые я бы выделил, поскольку очень важно знать и понимать, как они работают. К этим сигналам относятся SIGINT, SIGTERM и SIGKILL. Давайте посмотрим, что они из себя представляют.

Что такое сигнал Linux?

Мы все прекрасно знаем, что если на светофоре загорается красный свет, то пешеходы должны закончить переходить дорогу, а машины остановиться. Тоже самое и в системах Linux и Unix. Вы можете передать запущенной программе или службе некий сигнал, и таким образом с ней взаимодействовать. Например, вы можете подать программе сигнал SIGTERM, тем самым сообщив о том, что «загорелся красный сигнал светофора». 

Конечно, пешеходы могут продолжить переходить дорогу на красный свет, или машины могут продолжать ехать, но это может быть не очень безопасно для всех участников дорожного движения. Тоже касается и сигнала SIGTERM, который мы отправляем процессору – процесс/программа может просто проигнорировать этот сигнал. 

У каждого основного сигнала Linux есть свой номер (1-30+). Как правило, через какое-то время опытный пользователь Linux запоминает некоторые из них. Например, сигнал SIGTERM соответствует номеру 15. А вот сигнал под номером 9 (SIGKILL), вполне вероятно, знают практически все, так как с его помощью можно принудительно завершить процесс, тогда как в нашем примере с «красным сигналом» SIGTERM этого сделать нельзя.

htop displaying possible program signals

На этой картинке вы можете видеть главный экран htop. Эту довольно удобную утилиту можно установить с помощью команды sudo apt install htop в Ubuntu/Mint или с помощью команды sudo yum install htop в RedHat/Centos/Fedora. На этом экране есть ряд сигналов завершения и многих других. Вы можете передать процессу, который вы выберите справа, любой из этих сигналов. Для того, чтобы выбрать процесс, перемещайте курсор вверх/вниз, после чего вы можете отправить сигнал, нажав F9. 

SIGKILL и SIGTERM

Эти названия могут вам показаться немного жутковатыми, но, в конце концов, весь этот профессиональный жаргон Linux предназначен для того, чтобы «убивать» процессы. В основном сигнал -9 (SIGKILL) нужен только в тех случаях, когда процесс/программа зависает. Стоит отметить, что такие слова, как «программа» и «процесс», являются взаимозаменяемыми в данном контексте. По сути, процесс – это любая запущенная программа (или служба), которой был присвоен PID (Process IDentifier – идентификатор процесса). 

Давайте рассмотрим пример, в котором мы попробуем завершить запущенный фоновый процесс с помощью сигнала SIGKILL. Имейте в виду, что сигнал SIGKILL довольно разрушительный. Он завершит процесс в любом случае вне зависимости от того, что процесс собирался сделать с этим сигналом. Процесс может перехватывать или перенаправлять некоторые сигналы, но не все. 

Sending SIGKILL to a sleep process running in the background

Здесь мы запустили процесс sleep 1800 в фоновом режиме. Для этого в конце команды мы добавили символ &. Этот процесс стал первым ([1]) фоновым процессом с PID 574660. После чего мы «убили» этот фоновый процесс с помощью команды kill -9 574660, где -9 означает SIGKILL.

Несмотря на то, что процесс был завершен сразу же, мы не видим сообщения о завершении (о том, что фоновый процесс под номером 1 «убит», т.е. [1]+ Killed). Это произошло, поскольку ввод командной строки появился до того, как сообщение успело отобразиться, то есть операция по возвращению командной строки, оказалась более быстрой, чем операция по завершению процесса. 

Мы проверяем список процессов с помощью команды ps -ef | grep 574660. Мы видим некоторый вывод, который относится к команде grep, которую мы запустили. И также мы видим, что процесс sleep уже завершен.

Давайте понаблюдаем за тем же процессом, но здесь мы уже будем использовать SIGTERM. Введем команду kill -15 ${PID}, где ${PID} - это процесс, который мы хотим завершить.

Sending SIGTERM to a sleep process running in the background

Для того, чтоб вызвать/показать сообщение о завершении, мы нажали Enter (см. выше). Мы видим, что программа, как и в прошлый раз, завершилась корректно. Но на этот раз процесс внутри кода программы sleep был не совсем таким же, хотя в данном конкретном примере этого не видно (читайте дальше!).

В данном случае (когда для того, чтобы завершить процесс, мы использовали сигнал -15, т.е. SIGTERM) процесс sleep был уведомлен и смог на внутреннем уровне обработать этот сигнал. После обработки он мог завершиться самостоятельно, проигнорировать этот сигнал или ответить любым другим действием, которое было описано в коде. Мы можем убедиться в этом, если проверим выходной сигнал и/или вывод:

The difference in output and exit codes depending on the signal sent

 

Здесь мы запустили процесс sleep 2000 дважды. Для каждого запуска, чтобы завершить процесс, мы использовать разные оболочки/сеансы терминала. В первый раз для того, чтобы остановить процесс sleep мы использовали kill -9, а во второй - kill -15

Мы сразу можем заметить, что в первом примере возвращается Killed (после команды kill -9), то есть процесс был «убит», а во втором - Terminated (после команды kill -15), то есть процесс завершился самостоятельно. После чего мы проверили коды завершения и увидели, что они разные. 

Почему это так важно? В данном случае мы завершали простую команду sleep, а что если бы это была более масштабная программа? В нашем примере не происходило ничего серьезного, то есть данные не обрабатывались, трафик не пересылался туда/обратно и т.д. Но что будет, если мы отправим команду kill -9 на наш сервер базы данных (для этого, по большому счету, необходимы привилегии root/sudo)?

Это приведет к тому, что при следующем запуске базы данных она перейдет в режим аварийного восстановления. А все потому, то для программного обеспечения эта выглядит так: «там что-то было», а теперь здесь «ничего». Иными словами, произойдет сбой. А если бы мы ввели команду kill -15, то программное обеспечение базы данных могло бы выполнить контролируемое завершение, то есть сначала оно могло бы заблокировать подключение новых пользователей, затем отключить/завершить сеансы текущих пользователей, после чего закончить запись данных и т.д. и, наконец, самостоятельно завершиться. 

Как можно отправлять сигналы с помощью клавиатурных последовательностей?

А вы знаете, что каждый раз, когда вы отправляете запущенной программе последовательность клавиш CTRL+c, то вместо этого отправляется сигнал SIGINT? Давайте вернемся к нашему процессу sleep и проверим это:

A sleep process interrupted by a SIGINT signal sent via a CTRL+C key sequence

Мы снова запустили процесс sleep, после чего нажали комбинацию клавиш CTRL+c. Процесс завершился, точнее, был прерван сигналом SIGINT, который мы отправили. Мы запрашиваем код завершения и вновь видим, что этот код отличается от предыдущих. 

У каждого сигнала, который вы отправляете, есть свой код завершения (хотя, возможно, это касается не всех). Иными словами, когда вы используете в командной строке комбинацию клавиш CTRL+c, то у вас всегда будет код завершения 130, если вы будете «убивать» процесс с помощью команды kill -9, то код завершения будет 137, а если вы завершите процесс с помощью команды kill -15, то код завершения будет 143

Вы можете проверить код завершения, запросив переменную $? (пока вы не запустили новый процесс). Эта переменная содержит код завершения предыдущего процесса. Если вы будете знать код завершения какого-то конкретного процесса в конкретной ситуации и/или при отправке ему определенного сигнала, то это может помочь вам создать сценарии, которые будут обрабатывать другие процессы (это больше аргумент в пользу сценариев оболочки, особенно когда речь идет об управлении серверами или об автоматизированных средах).

Есть еще одна не менее популярная комбинация клавиш - CTRL+z. С ее помощью вы можете отправить сигнал приостановки SIGTSTP. При отправке этого сигнала, процесс будет немедленно приостановлен до тех пор, пока вы (например) не введете для того же процесса команду 'fg'. Эта команда снова запустит процесс.

Подытожим

В этой статье мы с вами рассмотрели самые важные сигналы Linux, а также то, как их можно применять в средах Linux и Unix. Знание этих сигналов может помочь вам использовать и управлять Linux на повседневной основе. Например, у вас завис какой-то процесс, тогда вы можете завершить его с помощью команды kill -9

Ссылка
скопирована
Программирование
Скидка 25%
Python-программист с нуля
Стань разработчиком на одном из самых популярных языков программирования.
Получи бесплатный
вводный урок!
Пожалуйста, укажите корректный e-mail
отправили вводный урок на твой e-mail!
Получи все материалы в telegram и ускорь обучение!
img
Еще по теме:
img
Введение Podman – это механизм управления OCI-контейнерами, который не требует запуска демон-процесса. Он нацелен на то, чтобы
img
За последние годы микросервисы прошли путь от обычного переоцененного модного словечка до вещи, которую вы, как специалист по пр
img
Введение Резидентные базы данных (или хранилища в памяти) по большей части делают упор на хранилище данных в памяти, а не на жес
img
  Многие люди рассуждают так: «зачем, ну зачем мне изучать еще один язык программирования?» Для них это лишнее, и они стараютс
img
Введение Объекты в Kubernetes – это базовые постоянные сущности, которые описывают состояние кластера Kubernetes. Модули – это э
img
  Ключевые отличия между JDK, JRE и JVM: JDK – это набор средств для разработки программного обеспечения, JRE – это програ
Комментарии
ЛЕТНИЕ СКИДКИ
40%
50%
60%
До конца акции: 30 дней 24 : 59 : 59