Перейти к содержанию

13.2 Управление процессами (Managing Processes)

Управление выполняющимися процессами — одна из ключевых задач администратора Linux. В данном разделе мы рассмотрим, как это делается. Будут затронуты следующие темы:

  • Запуск системных процессов
  • Просмотр выполняющихся процессов
  • Назначение приоритетов процессам
  • Управление процессами на переднем и фоновом планах
  • Завершение выполняющегося процесса
  • Сохранение процесса после выхода из системы

Начнём с изучения запуска процессов.

Запуск системных процессов (Starting System Processes)

Существует два основных способа запустить процесс в Linux. Для пользовательского процесса (user process) достаточно ввести имя команды или сценария в командной строке. Например, чтобы запустить программу vi, нужно просто ввести vi в командной строке. При этом создаётся процесс vi, как показано здесь:

rtracy@openSUSE:~> ps –a
  PID TTY          TIME CMD
 3719 pts/1    00:00:00 vi
 3729 pts/0    00:00:00 ps

Для системных процессов (system processes) используется либо сценарий init, либо служебный файл — в зависимости от того, применяет ли ваш дистрибутив процесс init или systemd. Если в дистрибутиве используется процесс init, то при загрузке системы он задействует сценарии init для запуска процессов. Эти сценарии хранятся в определённом каталоге системы Linux, который зависит от конкретного дистрибутива. Большинство дистрибутивов Linux используют один из двух типов сценариев init:

  • System V Дистрибутивы Linux, использующие сценарии System V init, хранят их в каталоге /etc/rc.d. Внутри /etc/rc.d находится ряд подкаталогов с именами от rc0.d до rc6.d. Каждый из этих каталогов соответствует определённому уровню выполнения. Внутри каждого подкаталога находятся символьные ссылки на сценарии init системных демонов, которые расположены в /etc/rc.d/init.d.

  • BSD Другие дистрибутивы Linux используют сценарии init в стиле BSD. Эти сценарии располагаются в каталоге /etc/init.d. Внутри /etc/init.d находится ряд каталогов с именами от rc0.d до rc6.d. Как и в случае сценариев System V init, эти каталоги привязаны к определённым уровням выполнения. Они содержат ссылки на сценарии init в /etc/init.d.

Помимо запуска этих сценариев через процесс init, их можно запускать непосредственно из командной строки. Для этого нужно ввести /etc/init.d/имя_сценария (для систем в стиле BSD) или /etc/rc.d/init.d/имя_сценария (для систем в стиле System V). Если вы не знаете нужное имя сценария, можно воспользоваться командой ls для получения списка сценариев в каталоге. Это показано на рисунке 13-6.

Рис. 13-6. Сценарии init в каталоге /etc/init.d.

Рис. 13-6. Сценарии init в каталоге /etc/init.d.

Набор сценариев в вашем каталоге init зависит от того, какие службы вы установили. Каждый раз при установке службы с помощью утилиты rpm соответствующий сценарий init автоматически помещается в каталог сценариев init. После этого любой сценарий можно запустить непосредственно из командной строки. Синтаксис (для систем в стиле BSD) выглядит следующим образом:

/etc/init.d/имя_сценария start | stop | restart

Например, чтобы запустить службу smb, нужно ввести /etc/init.d/smb start в командной строке. Для остановки — /etc/init.d/smb stop. Для перезапуска — /etc/init.d/smb restart.

В некоторых дистрибутивах для запуска, остановки или перезапуска служебного процесса можно также использовать сценарий rc без указания полного пути к файлу сценария. Синтаксис: rcимя_сценария start | stop | restart. Например, чтобы запустить службу smb, можно ввести rcsmb start в командной строке. Для остановки — rcsmb stop. Можно также использовать параметр restart для перезапуска.

Если в вашем дистрибутиве Linux вместо init используется процесс systemd, то управление системными службами осуществляется с помощью служебных файлов с расширением .service. Для запуска, остановки, перезапуска и проверки состояния служб используется команда systemctl:

  • Для запуска службы введите systemctl start имя_службы.
  • Для остановки службы введите systemctl stop имя_службы.
  • Для перезапуска службы введите systemctl restart имя_службы.
  • Для просмотра состояния службы введите systemctl status имя_службы.

Например, чтобы включить демон sshd в дистрибутиве с systemd, нужно ввести systemctl start sshd в командной строке.

Теперь, когда вы знаете, как запускать и останавливать системные процессы, перейдём к просмотру выполняющихся процессов.

Просмотр выполняющихся процессов (Viewing Running Processes)

В этой части раздела мы рассмотрим, как просматривать выполняющиеся процессы в системе. Будут рассмотрены следующие инструменты:

  • Использование top
  • Использование ps
  • Использование free
  • Использование pgrep

Начнём с утилиты top.

Использование top (Using top)

Linux предоставляет широкий выбор инструментов для просмотра выполняющихся процессов. Одним из наиболее удобных является утилита top. Она запускается простым вводом top в командной строке. После запуска отображается интерфейс, показанный на рисунке 13-7.

Рис. 13-7. Использование top для просмотра выполняющихся процессов.

Рис. 13-7. Использование top для просмотра выполняющихся процессов.

Как видно на рисунке 13-7, top отображает список выполняющихся процессов — по одному на каждой строке. Для отображения информации о каждом процессе используются следующие столбцы:

  • PID Идентификатор процесса (PID).
  • USER Имя пользователя, которому принадлежит процесс.
  • PR Приоритет, назначенный процессу. (Приоритеты процессов будут рассмотрены далее в этой главе.)
  • NI Значение «вежливости» процесса (nice value). (Что это означает — будет объяснено далее.)
  • VIRT Объём виртуальной памяти, используемой процессом.
  • RES Объём физической оперативной памяти, используемой процессом (резидентный размер), в килобайтах.
  • SHR Объём разделяемой памяти, используемой процессом.
  • S Состояние процесса. Возможные значения:
    • D Непрерываемый сон (Uninterruptibly sleeping)
    • R Выполняется (Running)
    • S Ожидание (Sleeping)
    • T Трассировка или остановка (Traced or stopped)
    • Z Зомби (Zombied)

Примечание

Процесс-зомби (zombied process) — это процесс, который завершил выполнение, но родительский процесс не получил уведомления о его завершении и не освободил PID дочернего процесса. Процесс-зомби может в конечном счёте самоустраниться. Если этого не происходит, может потребоваться принудительно завершить родительский процесс. Как это сделать — будет рассмотрено далее в главе.

  • %CPU Процент времени ЦП, используемого процессом.
  • %MEM Процент доступной физической оперативной памяти, используемой процессом.
  • TIME+ Общее время ЦП, потреблённое процессом с момента запуска.
  • COMMAND Имя команды, введённой для запуска процесса.

Главное достоинство top — динамичность. Экран постоянно обновляется, отражая актуальное состояние каждого процесса. Можно также сортировать информацию. Нажав клавишу h во время работы top, вы откроете экран справки с перечнем клавиш для сортировки по различным категориям. Этот экран показан на рисунке 13-8.

Рис. 13-8. Экран справки top.

Рис. 13-8. Экран справки top.

Этот экран также показывает, как использовать другие параметры top. Например, можно нажать f, чтобы отобразить список столбцов, которые можно добавить в вывод, как показано на рисунке 13-9.

Рис. 13-9. Добавление столбцов в вывод top.

Рис. 13-9. Добавление столбцов в вывод top.

Поля, которые будут отображаться, обозначены звёздочкой (*). Чтобы добавить или убрать поле, нужно перейти к нему стрелками и нажать пробел. Это переключает наличие звёздочки. Кроме того, можно нажать u, чтобы отображались только процессы, связанные с конкретным пользователем.

Утилита top очень удобна. Единственный её недостаток — она отображает только ограниченное число процессов. Иногда требуется увидеть все процессы, выполняющиеся в системе. В такой ситуации top не подходит, и нужно использовать утилиту ps.

Использование ps (Using ps)

Утилита ps позволяет отображать выполняющиеся процессы в системе. В отличие от top, которая показывает процессы динамически, ps выдаёт снимок текущих выполняющихся процессов.

Просто введя ps, можно просмотреть процессы, связанные с текущей оболочкой, как показано здесь:

openSUSE:~ # ps
  PID TTY           TIME CMD
 3946 pts/1     00:00:00 su
 3947 pts/1     00:00:00 bash
 3994 pts/1     00:00:00 ps

В этом примере ps отображает следующие процессы:

  • su Утилита su используется в этой оболочке для переключения на учётную запись суперпользователя root.
  • bash Текущий сеанс оболочки bash.
  • ps Поскольку ps используется для вывода списка текущих процессов, её собственный процесс также включается в список.

По умолчанию отображается следующая информация:

  • PID Идентификатор процесса.
  • TTY Имя терминальной сессии (оболочки), в которой выполняется процесс.
  • TIME Объём времени ЦП, использованного процессом.
  • CMD Имя команды, введённой для создания процесса.

Обратите внимание, что в списке оказалось только три процесса. На той системе, где выполнялась приведённая выше команда, выполнялось значительно больше процессов: в отдельной оболочке работал top, а также X-сервер и среда рабочего стола GNOME. Почему они не попали в список? По умолчанию ps показывает только процессы, связанные с текущей оболочкой. Поэтому в списке отображаются только оболочка, su и ps.

Чтобы увидеть все процессы, выполняющиеся в системе, нужно использовать параметр -e совместно с ps. Пример:

openSUSE:~ # ps –e
  PID TTY          TIME CMD
    1 ?        00:00:06 systemd
    2 ?        00:00:00 kthreadd
    3 ?        00:00:00 ksoftirqd/0
    5 ?        00:00:00 kworker/0:0H
    7 ?        00:00:00 migration/0
    8 ?        00:00:00 rcuc/0
    9 ?        00:00:00 rcub/0
   10 ?        00:00:01 rcu_preempt
   11 ?        00:00:00 rcu_bh
   12 ?        00:00:00 rcu_sched
   13 ?        00:00:00 watchdog/0
   14 ?        00:00:00 watchdog/1...

Как видно из этого примера, параметр -e приводит к отображению значительно большего числа процессов. Кроме того, обратите внимание, что у большинства показанных процессов в столбце TTY стоит знак ?. Это означает, что процесс является системным. Системные процессы (демоны) загружаются процессом init или systemd при запуске системы и потому не привязаны ни к какой оболочке. Именно поэтому в столбце TTY вывода ps для них отображается ?.

Можно также заметить, что объём отображаемой информации в ps довольно невелик по сравнению с top. Используя параметр -f совместно с ps, можно получить более подробный вывод. В следующем примере параметры -e и -f используются вместе для отображения расширенной информации о каждом процессе, выполняющемся в системе:

openSUSE:~ # ps –ef
UID        PID PPID         C STIME TTY               TIME CMD
root         1      0       0 17:41 ?             00:00:06 /sbin/init showopts
root         2      0       0 17:41 ?             00:00:00 [kthreadd]
root         3      2       0 17:41 ?             00:00:00 [ksoftirqd/0]
root         5      2       0 17:41 ?             00:00:00 [kworker/0:0H]
root         7      2       0 17:41 ?             00:00:00 [migration/0]
root         8      2       0 17:41 ?             00:00:00 [rcuc/0]
root         9      2       0 17:41 ?             00:00:00 [rcub/0]
root        10      2       0 17:41 ?             00:00:01 [rcu_preempt]
root        11      2       0 17:41 ?             00:00:00 [rcu_bh]
root        12      2       0 17:41 ?             00:00:00 [rcu_sched]
root        13      2       0 17:41 ?             00:00:00 [watchdog/0]
root        14      2       0 17:41 ?             00:00:00 [watchdog/1]...

С параметром -f становится доступна дополнительная информация, включая:

  • UID Идентификатор пользователя-владельца процесса.
  • PPID Идентификатор родительского процесса (PID).
  • C Объём времени процессора, использованного процессом.
  • STIME Время запуска процесса.

Для получения ещё более подробного вывода можно использовать параметр -l совместно с командой ps. Параметр -l отображает «длинный» формат вывода ps. Пример:

openSUSE:~ # ps –efl
F S UID        PID PPID           C PRI    NI ADDR SZ WCHAN STIME TTY              TIME CMD
1 S root         2    0           0 80      0 -     0 kthrea 11:09 ?           00:00:00 [kth]
1 S root         3    2           0 -40     - -     0 migrat 11:09 ?           00:00:00 [mig]
1 S root         4    2           0 80      0 -     0 run_ks 11:09 ?           00:00:00 [kso]
5 S root         5    2           0 -40     - -     0 watchd 11:09 ?           00:00:00 [wat]
1 S root         6    2           0 -40     - -     0 migrat 11:09 ?           00:00:00 [mig]
1 S root         7    2           0 80      0 -     0 run_ks 11:09 ?           00:00:00 [kso]
5 S root         8    2           0 -40     - -     0 watchd 11:09 ?           00:00:00 [wat]
1 S root         9    2           0 80      0 -     0 worker 11:09 ?           00:00:00 [eve]
1 S root        10    2           0 80      0 -     0 worker 11:09 ?           00:00:00 [eve]
1 S root        11    2           0 80      0 -     0 worker 11:09 ?           00:00:00 [net]
...

С параметром -l доступна следующая информация о выполняющихся процессах:

  • F Флаги, связанные с процессом. В этом столбце используются следующие коды:
    • 1 Ветвление выполнено, но exec не вызван
    • 4 Использованы привилегии суперпользователя root
  • S Состояние процесса. В этом столбце используются следующие коды:
    • D Непрерываемое ожидание (Uninterruptible sleep)
    • R Выполняется (Running)
    • S Прерываемое ожидание (Interruptible sleep)
    • T Остановлен или трассируется (Stopped or traced)
    • Z Зомби (Zombied)
  • PRI Приоритет процесса.
  • NI Значение «вежливости» процесса. (Что это означает — будет объяснено в следующем разделе.)
  • ADDR Адрес памяти процесса.
  • SZ Размер процесса.
  • WCHAN Имя функции ядра, в которой находится процесс в состоянии ожидания. Если процесс в данный момент выполняется, в этом столбце отображается дефис ().

Использование free (Using free)

Управление процессами в системе Linux подразумевает знание о том, сколько памяти используется и сколько её доступно. Как было сказано ранее, для просмотра этой информации можно использовать вывод top.

Также можно воспользоваться командой free. Команда free отображает объём свободной и выделенной оперативной памяти и памяти подкачки в системе. Параметр -m позволяет отображать статистику памяти в мегабайтах. Параметр -t отображает итоговые суммы по каждой категории информации. В следующем примере использована команда free –mt для просмотра статистики памяти:

openSUSE:~ # free –mt
             total             used          free        shared       buffers        cached
Mem:          1507              620           887             4            29           243
-/+ buffers/cache:              347          1160
Swap:         2053                0          2053
Total:        3561              620          2941

Использование pgrep (Using pgrep)

Команда ps очень полезна для просмотра информации о процессах. Однако её вывод иногда бывает чрезмерно объёмным, особенно если требуется найти один или два конкретных процесса. Один из вариантов — направить вывод ps в команду grep и отобразить только результаты, соответствующие заданным критериям.

Другой вариант — использовать команду pgrep. Как следует из её названия, pgrep объединяет функциональность команд ps и grep в одной утилите. При запуске pgrep задаются критерии отбора. Затем команда просматривает все выполняющиеся процессы и выводит список процессов, соответствующих этим критериям. Для формирования критериев отбора доступны следующие параметры:

  • -P ppid — поиск по указанному PID родительского процесса.
  • -f name — поиск по указанному имени процесса.
  • -u user_name — поиск по указанному владельцу процесса.

По умолчанию вывод pgrep содержит только PID совпавших процессов. Чтобы отобразить также имя процесса, нужно использовать параметр -l. Например, чтобы просмотреть список всех процессов, принадлежащих пользователю rtracy, можно использовать следующую команду:

openSUSE:~ # pgrep -l -u rtracy
3262 systemd
3264 (sd-pam)
3266 gnome-keyring-d
3269 gnome-session
3319 dbus-launch
3320 dbus-daemon
3322 ibus-daemon
3347 gvfsd
...

Теперь, когда вы знаете, как просматривать выполняющиеся процессы, перейдём к вопросу назначения приоритетов процессам.

Назначение приоритетов процессам (Prioritizing Processes)

Напомним, что Linux является многозадачной операционной системой. Она распределяет время ЦП между всеми выполняющимися процессами, создавая иллюзию их одновременного выполнения.

Поскольку Linux — это многозадачная операционная система, для каждого процесса можно задать уровень приоритета. Это определяет, сколько времени ЦП получит данный процесс относительно других.

По умолчанию Linux старается равномерно распределять время ЦП между всеми процессами. Однако иногда требуется скорректировать приоритет конкретного процесса. В зависимости от конфигурации системы может потребоваться предоставить определённому процессу более высокий приоритет по сравнению с остальными. Для этого существует ряд утилит Linux. В данной части главы будут рассмотрены следующие инструменты:

  • Установка приоритетов с помощью nice
  • Изменение приоритетов выполняющихся процессов с помощью renice

Начнём с изучения утилиты nice.

Установка приоритетов с помощью nice (Setting Priorities with nice)

Утилита nice позволяет запустить программу с отличным от стандартного уровнем приоритета. Напомним из предыдущего обсуждения top и ps, что каждый выполняющийся процесс имеет связанные с ним значения PR и NI. Это показано на рисунке 13-10.

Рис. 13-10. Просмотр значений PR и NI.

Рис. 13-10. Просмотр значений PR и NI.

Значение PR — это приоритет процесса с точки зрения ядра. Чем выше число, тем ниже приоритет процесса. Чем ниже число, тем выше приоритет. Значение NI — это значение «вежливости» (nice value) процесса. Оно учитывается в расчётах ядра при определении приоритета процесса. Значение «вежливости» для любого процесса Linux может находиться в диапазоне от –20 до +19. Чем ниже значение «вежливости», тем выше приоритет процесса.

Напрямую изменить приоритет процесса нельзя, но можно изменить его значение «вежливости». Проще всего сделать это при первоначальном запуске команды, создающей процесс. Для этого используется команда nice. Синтаксис: nice –n уровень_вежливости команда.

Например, предположим, что требуется запустить программу vi с повышенным приоритетом, уменьшив её значение «вежливости» до –5. До этого vi выполняется с приоритетом 80, как показано здесь:

openSUSE:~ # ps -el | grep vi
0 S 1000 8435 8425 2 80                  0 -   6823 -          pts/0       00:00:00 vi

Обратите внимание, что у процесса vi значение «вежливости» по умолчанию равно 0. Ядро использует это значение для вычисления общего приоритета процесса, который равен 80. Можно повысить приоритет этого процесса, введя nice –n –15 vi в командной строке. После этого значения приоритета и «вежливости» процесса vi уменьшатся, что означает повышение его приоритета в системе. Это показано в следующем примере:

openSUSE:~ # ps -el | grep vi
4 S     0 8488 8455 0 65 -15 -                 6533 -          pts/0       00:00:00 vi

Обратите внимание, что значение «вежливости» уменьшилось до –15. В результате общий приоритет процесса снизился до значения 65.

Следует учитывать, что Linux ограничивает возможность уменьшения значения «вежливости» для процессов. Поскольку Linux — многопользовательская операционная система, несколько пользователей могут одновременно изменять значения «вежливости» своих процессов. Разумеется, каждый пользователь считает свои процессы важнее остальных и может быть соблазнён установить значение «вежливости» –20 для почти всего, что он запускает.

Чтобы этого не происходило, Linux не разрешает снижать значение «вежливости» процесса ниже 0, если вы не вошли в систему как root. Иными словами, без прав суперпользователя использование отрицательных чисел с командой nice недоступно.

Команда nice отлично подходит для изменения значения «вежливости» при запуске команды. Но что делать, если нужно изменить приоритет уже выполняющегося процесса? В этом случае nice не подходит — нужно использовать команду renice.

Изменение приоритетов выполняющихся процессов с помощью renice (Setting Priorities of Running Processes with renice)

Вместо того чтобы завершать процесс и перезапускать его с другим значением «вежливости» через nice, можно использовать команду renice для изменения значения «вежливости» уже выполняющегося процесса. Синтаксис: renice значение_вежливости PID.

Например, в приведённом выше примере PID процесса vi равен 8488. Чтобы понизить приоритет этого процесса без его выгрузки, можно ввести renice 4 8488 в командной строке, как показано в следующем примере:

openSUSE:~ # renice 4 8488
8488: old priority -15, new priority 4
openSUSE:~ # ps -elf | grep vi
4 S root      8488 8455 0 84      4 - 6533 -                       08:40 pts/0        00:00:00 vi

Как видно из этого примера, значение «вежливости» процесса vi увеличилось с –15 до 4. В результате общий приоритет процесса вырос с 65 до 84, то есть его приоритет в системе снизился. Так же как и с nice, для установки отрицательного значения «вежливости» выполняющегося процесса необходимо быть вошедшим в систему как root.

Перейдём к обсуждению процессов на переднем и фоновом планах.

Управление процессами на переднем и фоновом планах (Managing Foreground and Background Processes)

В данной части главы будет рассмотрен запуск процессов на переднем (foreground) и фоновом (background) планах. Будут рассмотрены следующие темы:

  • Запуск процессов в фоновом режиме
  • Переключение процессов между фоновым и передним планами

Запуск процессов в фоновом режиме (Running Processes in the Background)

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

Это происходит потому, что процесс выполняется на переднем плане (foreground). Такое поведение особенно очевидно при запуске графического приложения из командной строки. На рисунке 13-11 приложение LibreOffice было запущено из командной строки командой libreoffice.

Рис. 13-11. Запуск графического приложения на переднем плане.

Рис. 13-11. Запуск графического приложения на переднем плане.

Обратите внимание на рисунке 13-11, что курсор в оболочке недоступен. Он останется недоступным до закрытия LibreOffice. Только после этого можно будет вводить дополнительные команды в этой командной строке.

Это поведение по умолчанию для всех команд, вводимых в командной строке, — как для текстовых программ оболочки, так и для графических программ. Однако программу можно запустить в фоновом режиме (background). При этом запущенная программа будет работать в обычном режиме, но управление сразу же вернётся к оболочке. Затем из оболочки можно запускать другие программы или выполнять другие задачи.

Запуск программы в фоновом режиме — очень простая операция. Достаточно добавить к команде символ амперсанда (&). Это указывает оболочке запустить программу в фоновом режиме. На рисунке 13-12 приложение LibreOffice снова запущено, но на этот раз к концу команды добавлен амперсанд, что приводит к его запуску в фоновом режиме.

Рис. 13-12. Запуск приложения в фоновом режиме.

Рис. 13-12. Запуск приложения в фоновом режиме.

Обратите внимание на рисунке 13-12, что после запуска процесса в фоновом режиме на экране отобразились два значения. Первое значение, [1], — идентификатор фонового задания (background job ID), присвоенного

фоновому заданию. Второе значение — PID процесса. Просмотреть все фоновые задания, выполняющиеся в системе, можно командой jobs:

rtracy@openSUSE:~> jobs
[1]+ Done                                               libreoffice &

В этом примере вывод команды jobs отображает состояние задания и имя команды, которая была запущена для создания фонового задания.

Переключение процессов между фоновым и передним планами (Switching Processes Between the Background and the Foreground)

То, что процесс был запущен на фоновом или переднем плане, не означает, что он должен там и оставаться. Можно переключать процесс между передним и фоновым планами во время его выполнения. Для этого используются следующие команды:

  • fg Эта команда переводит фоновый процесс на передний план. Синтаксис: fg идентификатор_задания.
  • bg Эта команда переводит процесс с переднего плана в фоновый режим. Для этого сначала нужно назначить процессу на переднем плане идентификатор фонового задания. Это делается нажатием ctrl-z. После этого процесс останавливается и ему назначается идентификатор фонового задания. Затем можно ввести bg идентификатор_задания для перевода процесса в фоновый режим.

В следующем примере программа vi была загружена в обычном режиме на переднем плане, затем остановлена с помощью ctrl-z, при этом ей был присвоен идентификатор задания 1. Затем она была отправлена в фоновый режим командой bg 1:

rtracy@openSUSE:~> vi

[1]+ Stopped                             vi
rtracy@openSUSE:~> bg 1
[1]+ vi &

Завершение выполняющегося процесса (Ending a Running Process)

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

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

  • С помощью kill и killall
  • С помощью pkill

Рассмотрим сначала использование команды kill.

Использование kill и killall (Using kill and killall)

Команда kill используется для завершения процесса. Синтаксис: kill –сигнал PID. Параметр PID — это идентификатор процесса, который нужно завершить. Также можно отправить процессу конкретный сигнал завершения. Всего существует около 64 различных типов сигналов. Наиболее полезные из них:

  • SIGHUP Это сигнал kill номер 1. Данный сигнал перезапускает процесс. После перезапуска процесс получает точно такой же PID, как и до этого. Это очень полезный параметр для перезапуска службы после внесения изменений в её конфигурационный файл.
  • SIGINT Это сигнал kill номер 2. Данный сигнал посылает процессу последовательность клавиш ctrl-c.
  • SIGKILL Это сигнал kill номер 9. Это «грубый» сигнал, принудительно завершающий процесс. Если процесс сильно завис, данный параметр заставит его остановиться. Однако при использовании этого сигнала процесс может не выполнить корректное завершение. Ресурсы, выделенные процессу, могут оставаться занятыми до перезагрузки системы.
  • SIGTERM Это сигнал kill номер 15. Данный сигнал предписывает процессу немедленно завершить работу. Это сигнал по умолчанию, отправляемый командой kill, если сигнал не указан явно. Этот сигнал позволяет процессу выполнить корректное завершение перед выходом.

При использовании kill можно указывать либо текстовое имя сигнала (например, SIGTERM), либо его номер (например, 15). Для использования kill сначала нужно с помощью ps или top определить PID процесса. В следующем примере процесс vi выполняется с PID 8312:

openSUSE:~ # ps
  PID TTY           TIME CMD
 8278 pts/0     00:00:00 su
 8279 pts/0     00:00:00 bash
 8312 pts/0     00:00:00 vi
 8313 pts/0     00:00:00 ps
openSUSE:~ # kill -SIGTERM 8312
openSUSE:~ #

В этом примере введена команда kill –SIGTERM 8312 для завершения процесса vi. Можно было также ввести kill –15 8312 и получить тот же результат. Поскольку сигнал SIGTERM позволяет процессу освободить ресурсы перед выходом, процесс vi завершается корректно.

Это подводит к типичной ошибке начинающих администраторов Linux при работе с kill: они сразу прибегают к самому жёсткому сигналу, не пробуя более мягкие варианты. Да, SIGKILL сработает, но лучше сначала попробовать другие, более «чистые» сигналы. Только если они не помогут, стоит прибегнуть к более жёсткому сигналу. Рекомендуемая последовательность действий при зависшем процессе:

  1. Сначала отправьте SIGINT. Если процесс не реагирует, перейдите к шагу 2.
  2. Отправьте SIGTERM. Обычно это решает проблему и позволяет процессу завершиться корректно. Если нет — перейдите к шагу 3.
  3. Отправьте SIGKILL.

Помимо kill, для завершения процессов можно использовать команду killall. Команда killall очень похожа на kill, синтаксис практически идентичен. Ключевое отличие состоит в том, что killall использует имя команды процесса, а не его PID. Например, если нужно завершить процесс vi из предыдущего примера с помощью killall вместо kill, нужно ввести killall –15 vi. Эта команда отправляет сигнал SIGTERM процессу с именем vi.

Настоятельно рекомендуется ознакомиться со страницей руководства для killall. Она весьма обширна и содержит полезную информацию. Например, там показано, как с помощью параметра -u завершать процессы, принадлежащие конкретному пользователю.

Использование pkill (Using pkill)

Помимо kill и killall, для остановки выполняющегося процесса можно использовать команду pkill. Команда pkill является «родственником» команды pgrep, рассмотренной ранее. Они используют одинаковые параметры и даже имеют общую страницу руководства.

С помощью pkill можно искать процессы, соответствующие заданным критериям, и отправлять им определённый сигнал завершения. Например, чтобы найти все выполняющиеся процессы с именем vi и отправить им сигнал SIGTERM, нужно ввести pkill -SIGTERM -f vi в командной строке.

Сохранение процесса после выхода из системы (Keeping a Process Running After Logout)

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

Широко используется сигнал разрыва соединения — SIGHUP (hang-up signal). Linux отслеживает, какие процессы запущены в каком терминальном сеансе. При выходе пользователя из терминального сеанса Linux отправляет сигнал SIGHUP всем программам, связанным с этим сеансом.

Обычно каждый процесс реагирует на SIGHUP ожидаемым образом. Однако можно настроить процесс на игнорирование сигналов SIGHUP, что позволит ему продолжать выполнение даже после завершения сеанса оболочки. Для этого используется утилита nohup. Это заставляет процесс, созданный командой, игнорировать все сигналы SIGHUP.

Например, предположим, что создан сценарий оболочки updatemydb, который автоматически обновляет базу данных из внешнего источника данных. Выполнение этого сценария занимает много времени (обычно всю ночь), и оставлять систему с активным сеансом на это время нежелательно. Можно ввести nohup updatemydb & в командной строке и затем выйти из системы. Если команда генерирует вывод, который обычно направляется в stdout, nohup перенаправит его в файл ~/nohup.out.

Важно отметить, что команда, запущенная под nohup, защищена только от сигналов SIGHUP. Все остальные сигналы завершения по-прежнему работают. Например, программу можно завершить во время её выполнения с помощью сигнала SIGTERM и команды kill.

Аналогичной командой является screen. Команда screen — интересная утилита, особенно полезная при удалённом доступе к системе Linux через SSH-соединение. Ключевое преимущество screen — возможность использовать несколько окон оболочки в рамках одного SSH-сеанса. Например, если запустить top удалённо в SSH-сеансе, то из-за особенностей работы SSH-клиента нельзя вводить другие команды до остановки top и возврата к командной строке, если не открывать несколько SSH-сеансов.

Используя screen, можно держать top запущенным, одновременно работая в командной строке через SSH-соединение и вводя дополнительные команды. Это особенно ценно тем, что screen может поддерживать активность SSH-сеанса даже при разрыве сетевого соединения. Можно даже отключаться и повторно подключаться к сеансу оболочки из разных мест, не останавливая и не перезапуская выполняемые процессы.

Прежде чем использовать screen, нужно убедиться, что он установлен в системе. Большинство дистрибутивов включают его по умолчанию, но некоторые — нет.

После установки screen запускается простым вводом screen в командной строке. При этом отображается экран приветствия с информацией о лицензии и использовании, который нужно пройти. После этого отобразится командная строка — внешне она выглядит обычно, но теперь вы находитесь внутри окна screen. Это окно функционирует как обычный сеанс оболочки: в нём можно выполнять команды и взаимодействовать с программами точно так же, как из любой другой командной строки.

Однако если нажать ctrl-a, то всё, что вводится после этого, передаётся команде screen, а не оболочке. Примеры:

  • Нажатие ctrl-a, затем ? отображает справку по screen.
  • Нажатие ctrl-a, затем c создаёт новое окно screen. Предыдущее окно остаётся активным вместе со всеми запущенными в нём процессами. Например, если в окне screen в SSH-сеансе выполнялся top, а нужно проверить почту, не останавливая top, можно открыть новое окно и работать с почтой, пока top продолжает работать в первом окне.
  • Нажатие ctrl-a, затем n переключает между открытыми окнами screen.
  • Нажатие ctrl-a, затем d отсоединяет (detach) текущее окно screen и возвращает в исходную командную строку. При этом всё, что выполнялось в окне, продолжает работу. Можно даже полностью выйти из сервера — всё будет продолжать работать в отсоединённом окне.
  • Ввод screen –r повторно подключает к отсоединённому окну screen. При наличии нескольких отсоединённых окон будет предложено выбрать, к какому из них подключиться.

Упражнение 13-1. Работа с процессами Linux (Exercise 13-1: Working with Linux Processes)

Упражнение 13-1. Работа с процессами Linux

В этом упражнении вы будете практиковаться в использовании команд оболочки для управления процессами в системе. Упражнение можно выполнить на виртуальной машине, поставляемой с этой книгой. Для правильно настроенной среды запустите снимок 13-1.

Совет

Посмотрите видеозапись упражнения 13-1 для ознакомления с порядком выполнения задания.

Выполните следующее:

  1. Загрузите систему Linux и войдите как обычный пользователь.
  2. Откройте терминальный сеанс.
  3. Переключитесь на учётную запись суперпользователя root, введя su – и пароль student.
  4. Потренируйтесь в запуске системных процессов: a. В командной строке введите systemctl status atd. Каков статус демона at? (В большинстве дистрибутивов демон atd по умолчанию не настроен для запуска.) b. Запустите демон atd, введя systemctl start atd в командной строке. c. Снова введите systemctl status atd в командной строке. Служба atd должна теперь отображаться как запущенная.
  5. Потренируйтесь в использовании top: a. В командной строке введите top. b. Просмотрите список выполняющихся процессов. c. Нажмите h для перехода к экрану справки top. Какая клавиша сортирует вывод по статистике ЦП? d. Нажмите t для сортировки по статистике ЦП. Какие процессы используют больше всего времени ЦП в вашей системе? e. Нажмите m для сортировки по использованию памяти. Какие процессы потребляют больше всего памяти? f. Добавьте столбцы, нажав f. g. Добавьте столбец PPID, нажав b, затем пробел. Теперь в выводе должен появиться PPID каждого процесса. h. Выйдите из top, нажав q.
  6. Потренируйтесь в использовании утилиты ps для просмотра процессов: a. В командной строке введите ps. Какие процессы связаны с текущим сеансом оболочки? b. Просмотрите все выполняющиеся процессы в системе, введя ps –ef | more в командной строке. c. Нажимайте пробел, пока не найдёте службу atd. Под каким именем пользователя выполняется atd? (В большинстве дистрибутивов — под пользователем at.) d. В командной строке введите ps –el | less. e. Найдите столбец состояния (S). f. Нажимайте пробел, пока не найдёте службу atd. Каков статус службы? (Поскольку она сейчас не используется, скорее всего, она находится в состоянии ожидания.)
  7. Потренируйтесь в управлении приоритетами процессов: a. В командной строке введите top. b. Каковы значения приоритета (PR) и «вежливости» (NI) для процесса top? (В большинстве дистрибутивов — 16 и 0.) c. Нажмите q для остановки top. d. В командной строке введите nice –n –20 top. Каковы теперь значения PR и NI для процесса top? e. Запишите PID процесса top. f. Откройте новое окно терминала и войдите как root. g. В командной строке измените значение «вежливости» работающего top, введя renice 1 PID_top. h. Переключитесь обратно в первый терминал, где запущен top. Каковы теперь его значения PR и NI? i. Нажмите q для выхода из top.
  8. Потренируйтесь в переключении процессов между передним и фоновым планами: a. Снова запустите top, введя top в командной строке. b. В терминале с запущенным top нажмите ctrl-z. c. Запишите номер идентификатора фонового задания, присвоенного процессу. d. В командной строке введите bg идентификатор_фонового_задания. Вывод top исчезнет, пока процесс выполняется в фоновом режиме. e. Нажмите ctrl-c. f. В командной строке введите fg идентификатор_фонового_задания. Вывод top снова появится, когда процесс перейдёт на передний план.
  9. Потренируйтесь в завершении процессов: a. Убедитесь, что top по-прежнему выполняется. b. Переключитесь в другой терминал, где вы вошли как root. c. В командной строке введите ps –e | grep top. d. Запишите PID процесса top. e. В командной строке введите kill –SIGTERM PID_top. f. Переключитесь обратно в терминал, где выполнялся top. Убедитесь, что top завершился. g. Снова запустите top в командной строке. h. Переключитесь обратно в другой терминал, где вы вошли как root. i. Завершите процесс top, введя killall –15 top. j. Переключитесь обратно в первое окно терминала и убедитесь, что top завершился.
  10. Потренируйтесь в использовании screen: a. При необходимости введите exit для возврата к обычной учётной записи пользователя. b. Нажмите Enter для выхода из экрана приветствия. c. В командной строке окна screen введите top. d. Нажмите ctrl-a, затем c для создания нового окна. e. В командной строке нового окна введите pgrep –l –f top. top должен по-прежнему выполняться, и его PID будет отображён. f. Нажмите ctrl-a, затем n. Вы должны переключиться обратно в окно с запущенным top. g. Нажмите ctrl-a, затем d для отсоединения текущего окна. h. Повторно подключитесь к окну с запущенным top, введя screen –r в командной строке. Окно top должно снова отобразиться. i. Выйдите из top, нажав Esc, затем выйдите из screen, введя exit.