Лекция №13 Сигналы в Linux
Прошлая лекция была посвящена процессам в Linux. Сегодня мы поговорим о взаимодействии процессом между собой, а также о том как мы можем воздействовать на процессы. Сначала посмотрим как процессы могу взаимодействовать между собой. Мы уже писали в командной строке конструкции подобные этой: less /etc/group | grep user . В этом примере процесс less взаимодействует с процессом grep посредством механизма, который называется неименований канал или пайп (pipe - канал). Мы не будем вдаваться в подробности, просто запомните, что посредством символа |, который можно в данном случае называть “пайпом” информация (результат выполнения) процесса less идет на вход другого процесса - grep. Таким образом один процесс передал информацию другому процессу.
Еще один способ общения процессов - это именованные каналы. Изучение именованный каналов не входит в этот курс, но на практическом примере расскажу, что это. Именованный канал можно создать командой mkfifo:
igor@adm-ubuntu:~/linux$ mkfifo my_pipe
igor@adm-ubuntu:~/linux$ ls -l | grep my_pipe
prw-r–r– 1 igor igor 0 2009-11-09 17:59 my_pipe
Теперь в одной консоли выполните команду:
igor@adm-ubuntu:~/linux$ echo Hello > my_pipe
Как видите команда не завершает свою работу, а ждет. Зарегистрируйтесь еще в одной консоли и выполните команду:
igor@adm-ubuntu:~/linux$ cat my_pipe
Hello
Если вернуться на первую консоль, то вы увидите, что команда echo завершила свою работу. Таким образом через именованный канал my_pipe команда (процесс) echo передала информацию (слово Hello) процессу cat, который ее принял и вывел на экран.
Давайте теперь рассмотрим основной способ “общения” процессов - сигналы. Один процесс при помощи ядра может передать другому процессу специальное числовое значение сигнала. Процесс вызывает функцию передачи сигнала и передает необходимую информацию (код сигнала, PID процесса) ядру. Ядро передает сигнал процессу получателю и отслеживает как этот сигнал обрабатывается. Сигналы обозначаются цифрами или мнемоническими обозначениями. Перечень сигналов можно вывести командой kill -l.
Мнемонические имена которые вы видите (SIGTERM, SIGINT, SIGKILL) начинаются с приставки SIG. Имена в этом виде используются в языках программирования таких как С. В интерпретаторе bash используются или числа или мнемонические имена, но без приставки SIG - TERM, INT, KILL.
Часть сигналов (INT, TERM) являются перехватываемыми. Это означает, что процесс при получении такого сигнала должен перейти на специальную подпрограмму, которая занимается обработкой сигнала. Если подпрограммы обработки нет (а ее написанием занимаются разработчики программы, которая выполняется в контексте процесса), то управление передается ядру, которое выполняет действия по умолчанию, описанные для каждого сигнала.
Часть сигналов являются такими которые можно заблокировать. Например, один процесс посылает сигнал TERM другому процессу, а он в свою очередь не закончил операции ввода/вывода. В таком случае второй процесс может заблокировать полученный сигнал (опять таки в обработчике сигнала) до момента выполнения необходимой операции ввода/вывода. Сигнал TERM - это сигнал корректного завершения работы процесса. Обработчик этого сигнала, должен выполнить все необходимые действия для правильного завершения работы.
И есть третья группа сигналов, которые не блокируются и для которых не нужны обработчики. Примером такого сигнала является сигнал KILL. Этот сигнал уничтожает процесс, так как для него нет обработчиков в процессах, то он будет обрабатываться ядром по умолчанию и так как он не блокируемый, то действия будут выполнятся немедленно.
Пока мы говорили о том как процессы “общаются” между собой с помощью сигналов. Но мы (пользователи) также можем посылать сигналы процессам. Например, комбинация клавиш Ctrl+C посылает процессу сигнал INT, который прерывает выполнение процесса. Если вы наберете в терминале команду sleep 100, то команда не вернет управление терминалу пока не завершится. Прервать выполнение этой команды можно нажав комбинацию клавиш Ctrl+C.
В чем же отличия между похожими сигналами INT, TERM, KILL (а также QUIT и HUP)? Несмотря на похожесть отличия есть:
Сигнал KILL не блокируется и не перехватывается и ведет к немедленному завершению процесса.
Сигнал INT в отличии от KILL является блокируемым сигналом и перехватываемым.
Сигнал TERM также является перехватываемым и блокируемым и предназначен для корректного (предпочтительного) завершения работы процесса.
Сигнал QUIT - похож на TERM, но позволяет сохранить дамп памяти.
Сигнал HUP - сейчас этот сигнал чаще всего интерпретируется процессами как “прочесть конфигурационные файлы”.
Рассмотрим два сигнала: STOP и CONT. Сигнал STOP останавливает процесс, то есть процесс переходит в состояние “остановленный“. В таком состоянии процесс будет до тех пор пока снова не получит сигнал. Если будет получен сигнал CONT, то процесс возобновит свою работу с того момента как он был остановлен. Практический пример:
Наберите в терминале команду sleep 1000 &.
Затем проверьте, что процесс находится в состоянии ожидания, о чем нам говорит буква S в столбце STAT:
igor@ubuntu:~$ ps x | grep [s]leep
PID TTY STAT TIME COMMAND
6301 pts/1 S 0:00 sleep 1000
Теперь пошлем процессу сигнал STOP. Для этого используем команду kill (kill -название процесса PID процесса):
igor@ubuntu:~$ kill -STOP 6301
[1]+ Stopped sleep 1000
Проверяем статус процесса:
igor@ubuntu:~$ ps x | grep [s]leep
PID TTY STAT TIME COMMAND
6301 pts/1 T 0:00 sleep 1000
Видим, что процесс действительно находится в состоянии “остановленный” (символ T в столбце STAT).
Теперь отправим процессу сигнал продолжения работы (CONT) и проверим состояние:
igor@ubuntu:~$ kill -CONT 6301
igor@ubuntu:~$ ps x | grep [s]leep
PID TTY STAT TIME COMMAND
6301 pts/1 S 0:00 sleep 1000
Если необходимо корректно завершить процесс, то необходимо послать ему сигнал TERM:
igor@ubuntu:~$ kill -TERM 6301
igor@ubuntu:~$ ps x | grep [s]leep
[1]+ Terminated sleep 1000
igor@ubuntu:~$ ps x | grep [s]leep
Если сразу же после посылки сигнала TERM выполнить команду ps x | grep [s]leep, то можно успеть увидеть сообщение о том, что процесс завершает работу, в при следующей попытке вывести информацию о нашем процессе sleep мы уже ничего не увидим - процесс прекратил существование. Команда kill без указания сигнала, по умолчанию передает процессу именно сигнал TERM. Поэтому можно было написать просто kill 6301.
Если необходимо срочно завершить процесс, или процесс не завершается по сигналу TERM, то тогда необходимо послать процессу сигнал KILL:
igor@ubuntu:~$ sleep 1000 &
[1] 6348
igor@ubuntu:~$ kill -KILL 6348
igor@ubuntu:~$ ps x | grep [s]leep
[1]+ Killed sleep 1000
Если необходимо послать один и тот же сигнал нескольким процессам, то можно перечислить их через пробел: kill -TERM 2345 3456 4567.
Команда kill довольно ограничена в возможностях и не позволяет выполнять более сложные действия. Поэтому рассмотрим еще одну команду - killall. Основное преимущество этой команды, то что она умеет посылать сигналы всем процессам с одинаковым именем или всем процессам одного пользователя. Запустите несколько раз подряд команду sleep 1000 &:
igor@ubuntu:~$ ps x | grep [s]leep
6460 pts/1 S 0:00 sleep 1000
6461 pts/1 S 0:00 sleep 1000
6462 pts/1 S 0:00 sleep 1000
6463 pts/1 S 0:00 sleep 1000
6464 pts/1 S 0:00 sleep 1000
6465 pts/1 S 0:00 sleep 1000
6466 pts/1 S 0:00 sleep 1000
Теперь, чтобы завершить все процессы с именем sleep, достаточно набрать команду killall sleep:
igor@ubuntu:~$ killall sleep
[1] Terminated sleep 1000
[2] Terminated sleep 1000
[3] Terminated sleep 1000
[4] Terminated sleep 1000
[6]- Terminated sleep 1000
[7]+ Terminated sleep 1000
[5]+ Terminated sleep 1000
Выполните команду sleep 1000 & еще несколько раз, а затем зарегистрируйтесь в другой консоли от имени другого пользователя (например, test) и также от его имени выполните команду sleep 1000 &. Теперь вернитесь в свою консоль и просмотрите процессы sleep всех пользователей:
igor@ubuntu:~$ ps aux | grep [s]leep
igor 6540 0.0 0.0 2952 628 pts/1 S 22:30 0:00 sleep 1000
igor 6541 0.0 0.0 2952 632 pts/1 S 22:30 0:00 sleep 1000
igor 6542 0.0 0.0 2952 628 pts/1 S 22:30 0:00 sleep 1000
test 6543 0.0 0.0 2952 632 pts/3 S 22:30 0:00 sleep 1000
test 6544 0.0 0.0 2952 628 pts/3 S 22:30 0:00 sleep 1000
test 6545 0.0 0.0 2952 628 pts/3 S 22:30 0:00 sleep 1000
test 6546 0.0 0.0 2952 632 pts/3 S 22:30 0:00 sleep 1000
Теперь для того, чтобы удалить процессы только пользователя test необходимо выполнить (от имени пользователя root) команду killall -u test:
igor@ubuntu:~$ sudo killall -u test
igor@ubuntu:~$ ps aux | grep [s]leep
igor 6540 0.0 0.0 2952 628 pts/1 S 22:30 0:00 sleep 1000
igor 6541 0.0 0.0 2952 632 pts/1 S 22:30 0:00 sleep 1000
igor 6542 0.0 0.0 2952 628 pts/1 S 22:30 0:00 sleep 1000
Команда выше удалит не только процессы sleep, но вообще все процессы пользователя test. Если необходимо удалить конкретно процессы sleep, то тогда команду нужно было записать так: killall -u test sleep.
Если запустить команду killall c ключом -i, то перед посылкой сигнала будет запрашиваться подтверждение:
igor@ubuntu:~$ killall -i sleep
Прибить sleep(6540) ? (y/N) n
Прибить sleep(6541) ? (y/N) n
Прибить sleep(6542) ? (y/N) n
Следующая лекция будет завершающей по теме процессов и сигналов Linux. Мы поговорим о заданиях (jobs), командах jobs, fg, bg, strong>nohup, и top.
IgorKa - Информационный ресурс » Лекция №12 - Процессы Linux. nice-фактор. Команда ps.:
[...] следующей лекции поговорим о [...]
19 января 2010, 9:55Dimon:
Желательно давать -1, затем -15 и только потом -9, если ничего не помогло- то делать перезагрузку (-1 - HUP отбой(желательно давать отбой перед KILL) | -9 - KILL грубое “убийство” процесса| -15 - TERM программное завершение процесса).
P.S.Это на всякий случай, может пригодится кому. Я сам всегда так поступаю и, практически никогда до KILL не доходит))
Ответить
30 июля 2010, 10:44Dimon:
Забыл сказать:
Желательно запускать sync перед каждым выключением системы, перезагрузкой, использованием команд “убийц” процессов и т.д.sync записывает все данные из буфера (буферный кеш) в память, начиная с inod. Желательно запускать sync перед каждым выключением системы, перезагрузкой, использованием команд “убийц” процессов и т.д.
Ответить
30 июля 2010, 10:51