Linux. Управление процессами

30.07.2023

Теги: CLILinuxКомандаПроцесс

Управление процессами в Linux — это довольно обширная тема. Но все сводится к одному, что мы различными способами меняем характеристики процессов. При этом мы можем преследовать совершенно разные цели — завершить или приостановить процесс, поменять ему приоритет, заставить работать в фоне и другое.

Сигналы

Сигналы нужны для оповещения процессов о разнообразных событиях в системе. Это могут быть события оборудования или события других процессов. Если процесс получает сигнал, то он прерывает свою обычную работу, обрабатывает сигнал, а затем продолжает работать.

Сигналы от ядра поступают процессам напрямую. А сигналы от одних процессов другим поступают через ядро, то есть с помощью системных вызовов. Системный вызов, который обрабатывает сигналы называется kill(). Его так назвали, так как большинство стандартных сигналов завершают (убивают) процесс.

Список всех сигналов можно посмотреть с помощью команды

$ kill -l
 1) SIGHUP         2) SIGINT         3) SIGQUIT        4) SIGILL         5) SIGTRAP
 6) SIGABRT        7) SIGBUS         8) SIGFPE         9) SIGKILL       10) SIGUSR1
11) SIGSEGV       12) SIGUSR2       13) SIGPIPE       14) SIGALRM       15) SIGTERM
16) SIGSTKFLT     17) SIGCHLD       18) SIGCONT       19) SIGSTOP       20) SIGTSTP
21) SIGTTIN       22) SIGTTOU       23) SIGURG        24) SIGXCPU       25) SIGXFSZ
26) SIGVTALRM     27) SIGPROF       28) SIGWINCH      29) SIGIO         30) SIGPWR
31) SIGSYS        34) SIGRTMIN      35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9    44) SIGRTMIN+10   45) SIGRTMIN+11   46) SIGRTMIN+12   47) SIGRTMIN+13
48) SIGRTMIN+14   49) SIGRTMIN+15   50) SIGRTMAX-14   51) SIGRTMAX-13   52) SIGRTMAX-12
53) SIGRTMAX-11   54) SIGRTMAX-10   55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1    64) SIGRTMAX

Давайте рассмотрим более подробно некоторые из них

  • SIGHUP (1) — разрыв с управляющим терминалом. Процесс либо что-то предпримет (если программист об этом позаботился), либо завершится. Например, мы работотаем с сервером, подключившись к нему по ssh. И вдруг связь пропадает, ssh сессия обрывается. Все наши процессы неожиданно теряют управляющий терминал и начинают завершаться, так как получают от ядра этот сигнал.
  • SIGINT (2) — клавиатурный сигнал, срабатывает когда мы нажимаем Ctrl+c. Это штатное завершение, то есть процесс будет завершён корректно (если процесс вообще умеет завершаться корректно).
  • SIGQUIT (3) — клавиатурный сигнал, срабатывает когда мы нажимаем Ctrl+\. Аварийное завершение с выдачей отладочной информации.
  • SIGABRT (6) — это аналог SIGQUIT (3). Если у процесса нет управляющего терминала, то отправить ему клавиатурный сигнал не получится, поэтому используется этот сигнал.
  • SIGKILL (9) — этот сигнал сразу завершает процесс (некорректно). И это поведение нельзя изменить, то есть программист не может сам указать программе, что делать в случае получения этого сигнала.
  • SIGTERM (15) — это аналог SIGINT (2). Если у процесса нет управляющего терминала, то отправить ему клавиатурный сигнал не получится, поэтому используется этот сигнал.
  • SIGTSTP (20) — клавиатурный сигнал, когда мы нажимаем Ctrl+z. Этот сигнал приостанавливает процесс на управляющем терминале и переводит процесс на задний фон. То есть процесс переходит в состояние T (stopped by job control signal — остановленный специальным сигналом).

Команда kill

Команда позволяет отправлять сигналы процессам. Тип сигнала указывается как опция в виде номера (например, -9) или имени (например, -SIGKILL). В качестве аргумента нужно указать PID процесса, которому мы отправляем сигнал. Если тип сигнала не указан, то будет отправлен сигнал SIGTERM.

$ kill -9 9898
$ kill -SIGKILL 2565

Так можно отправить сигнал своему процессу, но если нужно отправить сигнал чужому — используем команду sudo.

Команда pgrep

Команда позволяет находить идентификатор процесса на основе заданных критериев. Это может быть полное или частичное имя процесса, имя пользователя, запустившего процесс или другие критерии.

$ pgrep --help
Использование:
 pgrep [параметры] <шаблон>

Параметры:
 -d, --delimiter <строка>  указать разделитель вывода
 -l, --list-name           выводить PID и имена процессов
 -a, --list-full           выводить PID и полную командную строку
 -v, --inverse             negates the matching
 -w, --lightweight         выводить все TID
 -c, --count               вывод количества соответствующих шаблону процессов
 -f, --full                use full process name to match
 -g, --pgroup <PGID,...>   match listed process group IDs
 -G, --group <GID,...>     match real group IDs
 -i, --ignore-case         match case insensitively
 -n, --newest              select most recently started
 -o, --oldest              select least recently started
 -P, --parent <PPID,...>   match only child processes of the given parent
 -s, --session <SID,...>   match session IDs
 -t, --terminal <tty,...>  match by controlling terminal
 -u, --euid <ID,...>       match by effective IDs
 -U, --uid <ID,...>        match by real IDs
 -x, --exact               match exactly with the command name
 -F, --pidfile <файл>      читать PIDы из файла
 -L, --logpidfile          fail if PID file is not locked
 -r, --runstates <state>   match runstates [D,S,Z,...]
 --ns <PID>                match the processes that belong to the same
                           namespace as <pid>
 --nslist <ns,...>         list which namespaces will be considered for
                           the --ns option.
                           Available namespaces: ipc, mnt, net, pid, user, uts

 -h, --help     вывести эту справку и выйти
 -V, --version  вывести информацию и выйти

Шаблон имени задается с использованием расширенных регулярных выражений. Когда команда вызывается без опций — будут показаны PID всех запущенных процессов, которые соответствуют указанному имени.

$ pgrep ssh
1039
2257
6850

Команда возвращает ноль, когда хотя бы один запущенный процесс соответствует запрошенному имени. В противном случае код выхода — единица. Это может быть полезно при использовании в сценариях оболочки.

Опция -d позволяет указать другой разделитель вместо символа новой строки

$ pgrep -d' ' ssh
1039 2257 6850

Команда pkill

Команда позволяет отправлять управляющий сигнал процессу на основе заданных критериев. Это может быть полное или частичное имя процесса, имя пользователя, запустившего процесс или другие критерии.

$ pkill --help
Использование:
 pkill [параметры] <шаблон>

Параметры:
 -<sig>, --signal <sig>    сигнал для отправки (число или имя)
 -q, --queue <value>       integer value to be sent with the signal
 -e, --echo                display what is killed
 -c, --count               вывод количества соответствующих шаблону процессов
 -f, --full                use full process name to match
 -g, --pgroup <PGID,...>   match listed process group IDs
 -G, --group <GID,...>     match real group IDs
 -i, --ignore-case         match case insensitively
 -n, --newest              select most recently started
 -o, --oldest              select least recently started
 -O, --older <seconds>     select where older than seconds
 -P, --parent <PPID,...>   match only child processes of the given parent
 -s, --session <SID,...>   match session IDs
 -t, --terminal <tty,...>  match by controlling terminal
 -u, --euid <ID,...>       match by effective IDs
 -U, --uid <ID,...>        match by real IDs
 -x, --exact               match exactly with the command name
 -F, --pidfile <файл>      читать PIDы из файла
 -L, --logpidfile          fail if PID file is not locked
 -r, --runstates <state>   match runstates [D,S,Z,...]
 --ns <PID>                match the processes that belong to the same
                           namespace as <pid>
 --nslist <ns,...>         list which namespaces will be considered for
                           the --ns option.
                           Available namespaces: ipc, mnt, net, pid, user, uts

 -h, --help     вывести эту справку и выйти
 -V, --version  вывести информацию и выйти

Шаблон имени задается с использованием расширенных регулярных выражений. Тип сигнала указывается как опция в виде номера (например, -9) или имени (например, -SIGKILL). Если тип сигнала не указан, то будет отправлен сигнал SIGTERM.

Чтобы перезапустить процессы веб-сервера Nginx, выполянем команду

$ pkill -SIGHUP nginx

Перед использованием команды pkill — полезно запустить команду pgrep для проверки

$ pgrep ssh
1039 sshd
2257 ssh-agent
6850 ssh

Если шаблон затрагивает процессы, которым не нужно отправлять сигнал — требуется уточнение

$ pkill '^ssh$'

Здесь символ ^ соответствует началу строки, а символ $ — концу строки. Так что в итоге будет выбран процесс ssh и не затронуты sshd и ssh-agent.

По умолчанию шаблон сопоставляется только с именем процесса. При использовании опции -f — шаблон сопоставляется с полными списком аргументов.

$ pkill -9 -f "ping 8.8.8.8"

Опция -u предписывает отправить сигнал процессам, запущенным указанным пользователем.

$ pkill -u evgeniy

Можно комбинировать опции и шаблон поиска. Команда ниже отправит сигнал SIGKILL всем процессам, запущенным пользователем evgeniy и соответствующим шаблону gnome.

$ pkill -SIGKILL -u evgeniy gnome

Команда killall

Команда killall очень похожа на pkill, но принимает в качестве аргумента имя процесса, а не шаблон имени. То есть, если вместо «firefox» указать «firef», то pkill закроет все процессы браузера Firefox, а killall не закроет ни одного процесса.

$ killall --help
Использование: killall [ПАРАМЕТР]… [--] ИМЯ…
       killall -l, --list
       killall -V, --version

  -e,--exact           требовать полного совпадения для очень длинных имён
  -I,--ignore-case     игнорировать регистр символов в именах процессов
  -g,--process-group   завершать группу процесса вместо одного процесса
  -y,--younger-than    завершить процессы, новее чем заданного ВРЕМЕНИ
  -o,--older-than      завершить процессы, старее чем заданного ВРЕМЕНИ
  -i,--interactive     запрашивать подтверждение перед завершением процессов
  -l,--list            вывести список допустимых имён сигналов
  -q,--quiet           не показывать подробные сообщения
  -r,--regexp          рассматривать ИМЯ как расширенное регулярное выражение
  -s,--signal СИГНАЛ   посылать указанный СИГНАЛ, а не SIGTERM
  -u,--user ПОЛЬЗВ     завершить процесс(ы), запущенный только ПОЛЬЗОВАТЕЛЕМ
  -v,--verbose         уведомлять только при успешной отправке сигнала
  -V,--version         показать информацию о версии
  -w,--wait            ожидать завершения процессов
  -n,--ns PID          все процессы, принадлежащие тем же пространствам имён
                       что и PID
  -Z,--context REGEXP  прибивать только процессы, имеющие контекст
                       (настройка должна предваряться другими аргументами)

Работа в фоне

Управление процессами можно применять и для того, чтобы в терминале можно было запускать процессы в фоновом режиме. Представьте, что при чтении справки man потребовалось выполнить пару команд. Чтобы не закрывать справку, можно нажать Ctrl+z и приостановить man. При этом работа man не просто приостанавливается, она уходит на задний фон.

$ man killall
тут нажатие Ctrl+z
[1]+  Остановлен    man killall

Теперь можно выполнить несколько команд в терминале. Давайте посмотрим, какие процессы выполняются в фоне.

$ jobs
[1]+  Остановлен    man killall

Мы видим только одно фоновое задание с номером 1. Знак плюс означает, что это текущее фоновое задание. Перевести фоновое задание на передний план можно с помощью команды fg номер. Если номер не указан — на передний план будет выведено текущее фоновое задание.

$ fg

И мы опять вернулись к чтению справки man.

Процесс на заднем фоне может быть не только в приостановленном состоянии. Если выполнение процесса не требует от нас каких-то интерактивных действий (никакого ввода или вывода), то можно заставить процесс выполнятся на заднем фоне. Для этого нужно выполнить команду bg номер.

Для примера, начнем скачивание большого файла с помощью wget

$ wget https://releases.ubuntu.com/22.04.1/ubuntu-22.04.1-desktop-amd64.iso

Затем переведём процесс скачивания на задний фон с помощью Ctrl+z

$ jobs
[1]+  Остановлен    wget https://releases.ubuntu.com/22.04.1/ubuntu-22.04.1-desktop-amd64.iso

Теперь, с помощью команды bg, запустим процесс на заднем фоне

$ bg 1
[1]+ wget https://releases.ubuntu.com/22.04.1/ubuntu-22.04.1-desktop-amd64.iso &
Вывод перенаправляется в wget-log

Утилита wget должна выводить информацию о скачивании файла, но на заднем фоне запрещено выводить информацию на терминал. Именно поэтому весь вывод автоматически перенаправляется в файл wget-log.

Проверим, что процесс скачивания теперь выполняется в фоновом режиме

$ jobs
[1]+  Запущен          wget https://releases.ubuntu.com/22.04.1/ubuntu-22.04.1-desktop-amd64.iso &

Запустить процесс на заднем фоне можно только, если он не интерактивный. Например запустить остановленный man не получится. Как только man попытается вывести на терминал справку, то сразу опять будет остановлен.

Приоритеты процессов

В работающей системе выполняется множество процессов. И каждому запущенному процессу назначается приоритет. Как ни странно, но чем больше числовое значение приоритета, тем меньше сам приоритет. То есть, процесс с числовым значением приоритета 10 будет более важным с точки зрения системы, чем процесс с числовым значением приоритета 20.

Пользователи не могут управлять приоритетами процессов, даже суперпользователь root. Но могут управлять другим значением — nice (вежливость, любезность), который варьируется от -20 до +19. По умолчанию, процесс созданный пользователем, имеет значение nice равное нулю, и приоритет равный 20.

$ ps -u evgeniy -o user,pid,nice,priority,cmd
USER         PID  NI PRI CMD
evgeniy      711   0  20 /usr/bin/python3 -m http.server 8081 --directory=/ho...
evgeniy     1224   0  20 /lib/systemd/systemd --user
evgeniy     1225   0  20 (sd-pam)
evgeniy     1243 -11   9 /usr/bin/pipewire
evgeniy     1244   0  20 /usr/bin/pipewire-media-session
evgeniy     1245 -11   9 /usr/bin/pulseaudio --daemonize=no --log-target=journal
evgeniy     1253   0  20 /usr/bin/gnome-keyring-daemon --daemonize --login

Разница в том, что priority — это реальный приоритет процесса в данный момент, а nice — подсказка для ядра, указывающая нужно ли увеличить или уменьшить приоритет процессу.

Кроме команлы ps, для просмотра приоритетов процессов можно использовать команды top и htop.

Команда nice

Команда настраивает приоритет процесса перед его запуском. Например, запустим две программы с разным приоритетом. Чтобы запустить их две в одном терминал — запустим выполнение на заднем фоне.

$ nice -15 md5sum /dev/urandom
Ctrl+z
$ bg
$ nice -5 md5sum /dev/urandom
Ctrl+z
$ bg
$ jobs
[1]-  Запущен          nice -15 md5sum /dev/urandom &
[2]+  Запущен          nice -5 md5sum /dev/urandom &

Теперь, с помощью ps, посмотрим на приоритеты процессов

$ ps -C md5sum -o user,pid,nice,priority,cmd,pcpu
USER         PID  NI PRI CMD                         %CPU
evgeniy    28958  15  35 md5sum /dev/urandom         10.0
evgeniy    28970   5  25 md5sum /dev/urandom         60.8

Как видите, команды md5sum работают параллельно — но у одной команды приоритет стал 25, а у другой 35.

Теперь запустим еще один экземпляр md5sum, но уменьшим nice, тем самым увеличив приоритет. Делать это надо с помощью sudo, так как обычный пользователь не имеет право запускать процессы с повышенным приоритетом.

$ sudo nice --5 md5sum /dev/urandom
Ctrl+z
$ bg
$ jobs
[1]   Запущен          nice -15 md5sum /dev/urandom &
[2]-  Запущен          nice -5 md5sum /dev/urandom &
[3]+  Запущен          sudo nice --5 md5sum /dev/urandom &

Теперь, с помощью ps, посмотрим на приоритеты процессов

$ ps -C md5sum -o user,pid,nice,priority,cmd,pcpu
USER         PID  NI PRI CMD                         %CPU
evgeniy    28958  15  35 md5sum /dev/urandom          6.0
evgeniy    28970   5  25 md5sum /dev/urandom         34.1
root       28984  -5  15 md5sum /dev/urandom         40.2

Последний запущенный процесс сильнее всего нагружает процессор.

Команда renice

Команда позволяет изменить приоритет уже работающего процесса. Этой командой может пользоваться только пользователь root. Вернем все процессам nice по умолчанию, то есть ноль.

$ sudo renice -n 0 -p 28958
28958 (process ID) старый приоритет 15, новый приоритет 0
$ sudo renice -n 0 -p 28970
28970 (process ID) старый приоритет 5, новый приоритет 0
$ sudo renice -n 0 -p 28984
28984 (process ID) старый приоритет -5, новый приоритет 0
$ ps -C md5sum -o user,pid,nice,priority,cmd,pcpu
USER         PID  NI PRI CMD                         %CPU
evgeniy    28958   0  20 md5sum /dev/urandom         13.0
evgeniy    28970   0  20 md5sum /dev/urandom         32.4
root       28984   0  20 md5sum /dev/urandom         47.6

Поиск: CLI • Linux • Команда • Сигнал • Процесс • pgrep • pkill • nice

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.