Debian процессы. Процессы в Linux, взаимодействие процессов. Получение информации о процессе

В этой статье я хотел бы рассказать о том, какой жизненный путь проходят процессы в семействе ОС Linux. В теории и на примерах я рассмотрю как процессы рождаются и умирают, немного расскажу о механике системных вызовов и сигналов.

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

Всё написанное ниже справедливо к Debian Linux с ядром 4.15.0.

Атрибуты процесса

Процесс в ядре представляется просто как структура с множеством полей (определение структуры можно прочитать ).
Но так как статья посвящена системному программированию, а не разработке ядра, то несколько абстрагируемся и просто акцентируем внимание на важных для нас полях процесса:
  • Идентификатор процесса (pid)
  • Открытые файловые дескрипторы (fd)
  • Обработчики сигналов (signal handler)
  • Текущий рабочий каталог (cwd)
  • Переменные окружения (environ)
  • Код возврата

Жизненный цикл процесса


Рождение процесса

Только один процесс в системе рождается особенным способом - init - он порождается непосредственно ядром. Все остальные процессы появляются путём дублирования текущего процесса с помощью системного вызова fork(2) . После выполнения fork(2) получаем два практически идентичных процесса за исключением следующих пунктов:
  1. fork(2) возвращает родителю PID ребёнка, ребёнку возвращается 0;
  2. У ребёнка меняется PPID (Parent Process Id) на PID родителя.
После выполнения fork(2) все ресурсы дочернего процесса - это копия ресурсов родителя. Копировать процесс со всеми выделенными страницами памяти - дело дорогое, поэтому в ядре Linux используется технология Copy-On-Write.
Все страницы памяти родителя помечаются как read-only и становятся доступны и родителю, и ребёнку. Как только один из процессов изменяет данные на определённой странице, эта страница не изменяется, а копируется и изменяется уже копия. Оригинал при этом «отвязывается» от данного процесса. Как только read-only оригинал остаётся «привязанным» к одному процессу, странице вновь назначается статус read-write.

Пример простой бесполезной программы с fork(2)

#include #include #include #include #include int main() { int pid = fork(); switch(pid) { case -1: perror("fork"); return -1; case 0: // Child printf("my pid = %i, returned pid = %i\n", getpid(), pid); break; default: // Parent printf("my pid = %i, returned pid = %i\n", getpid(), pid); break; } return 0; }

$ gcc test.c && ./a.out my pid = 15594, returned pid = 15595 my pid = 15595, returned pid = 0

Состояние «готов»

Сразу после выполнения fork(2) переходит в состояние «готов».
Фактически, процесс стоит в очереди и ждёт, когда планировщик (scheduler) в ядре даст процессу выполняться на процессоре.

Состояние «выполняется»

Как только планировщик поставил процесс на выполнение, началось состояние «выполняется». Процесс может выполняться весь предложенный промежуток (квант) времени, а может уступить место другим процессам, воспользовавшись системным вывозом sched_yield .

Перерождение в другую программу

В некоторых программах реализована логика, в которой родительский процесс создает дочерний для решения какой-либо задачи. Ребёнок в данном случае решает какую-то конкретную проблему, а родитель лишь делегирует своим детям задачи. Например, веб-сервер при входящем подключении создаёт ребёнка и передаёт обработку подключения ему.
Однако, если нужно запустить другую программу, то необходимо прибегнуть к системному вызову execve(2) :

Int execve(const char *filename, char *const argv, char *const envp);
или библиотечным вызовам execl(3), execlp(3), execle(3), execv(3), execvp(3), execvpe(3) :

Int execl(const char *path, const char *arg, ... /* (char *) NULL */); int execlp(const char *file, const char *arg, ... /* (char *) NULL */); int execle(const char *path, const char *arg, ... /*, (char *) NULL, char * const envp */); int execv(const char *path, char *const argv); int execvp(const char *file, char *const argv); int execvpe(const char *file, char *const argv, char *const envp);
Все из перечисленных вызовов выполняют программу, путь до которой указан в первом аргументе. В случае успеха управление передаётся загруженной программе и в исходную уже не возвращается. При этом у загруженной программы остаются все поля структуры процесса, кроме файловых дескрипторов, помеченных как O_CLOEXEC , они закроются.

Как не путаться во всех этих вызовах и выбирать нужный? Достаточно постичь логику именования:

  • Все вызовы начинаются с exec
  • Пятая буква определяет вид передачи аргументов:
    • l обозначает list , все параметры передаются как arg1, arg2, ..., NULL
    • v обозначает vector , все параметры передаются в нуль-терминированном массиве;
  • Далее может следовать буква p , которая обозначает path . Если аргумент file начинается с символа, отличного от "/", то указанный file ищется в каталогах, перечисленных в переменной окружения PATH
  • Последней может быть буква e , обозначающая environ . В таких вызовах последним аргументом идёт нуль-терминированный массив нуль-терминированных строк вида key=value - переменные окружения, которые будут переданы новой программе.

Пример вызова /bin/cat --help через execve

int main() { char* args = { "/bin/cat", "--help", NULL }; execve("/bin/cat", args, environ); // Unreachable return 1; }

$ gcc test.c && ./a.out Usage: /bin/cat ... ... Concatenate FILE(s) to standard output. *Вывод обрезан*


Семейство вызовов exec* позволяет запускать скрипты с правами на исполнение и начинающиеся с последовательности шебанг (#!).

Пример запуска скрипта с подмененным PATH c помощью execle

#define _GNU_SOURCE #include int main() { char* e = {"PATH=/habr:/rulez", NULL}; execle("/tmp/test.sh", "test.sh", NULL, e); // Unreachable return 1; }

$ cat test.sh #!/bin/bash echo $0 echo $PATH $ gcc test.c && ./a.out /tmp/test.sh /habr:/rulez


Есть соглашение, которое подразумевает, что argv совпадает с нулевым аргументов для функций семейства exec*. Однако, это можно нарушить.

Пример, когда cat становится dog с помощью execlp

#define _GNU_SOURCE #include int main() { execlp("cat", "dog", "--help", NULL); // Unreachable return 1; }

$ gcc test.c && ./a.out Usage: dog ... ... *Вывод обрезан*


Любопытный читатель может заметить, что в сигнатуре функции int main(int argc, char* argv) есть число - количество аргументов, но в семействе функций exec* ничего такого не передаётся. Почему? Потому что при запуске программы управление передаётся не сразу в main. Перед этим выполняются некоторые действия, определённые glibc, в том числе подсчёт argc.

Состояние «ожидает»

Некоторые системные вызовы могут выполняться долго, например, ввод-вывод. В таких случаях процесс переходит в состояние «ожидает». Как только системный вызов будет выполнен, ядро переведёт процесс в состояние «готов».
В Linux так же существует состояние «ожидает», в котором процесс не реагирует на сигналы прерывания. В этом состоянии процесс становится «неубиваемым», а все пришедшие сигналы встают в очередь до тех пор, пока процесс не выйдет из этого состояния.
Ядро само выбирает, в какое из состояний перевести процесс. Чаще всего в состояние «ожидает (без прерываний)» попадают процессы, которые запрашивают ввод-вывод. Особенно заметно это при использовании удалённого диска (NFS) с не очень быстрым интернетом.

Состояние «остановлен»

В любой момент можно приостановить выполнение процесса, отправив ему сигнал SIGSTOP. Процесс перейдёт в состояние «остановлен» и будет находиться там до тех пор, пока ему не придёт сигнал продолжать работу (SIGCONT) или умереть (SIGKILL). Остальные сигналы будут поставлены в очередь.

Завершение процесса

Ни одна программа не умеет завершаться сама. Они могут лишь попросить систему об этом с помощью системного вызова _exit или быть завершенными системой из-за ошибки. Даже когда возвращаешь число из main() , всё равно неявно вызывается _exit .
Хотя аргумент системного вызова принимает значение типа int, в качестве кода возврата берется лишь младший байт числа.

Состояние «зомби»

Сразу после того, как процесс завершился (неважно, корректно или нет), ядро записывает информацию о том, как завершился процесс и переводит его состояние «зомби». Иными словами, зомби - это завершившийся процесс, но память о нём всё ещё хранится в ядре.
Более того, это второе состояние, в котором процесс может смело игнорировать сигнал SIGKILL, ведь что мертво не может умереть ещё раз.

Забытье

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

Pid_t wait(int *wstatus); /* Аналогично waitpid(-1, wstatus, 0) */ pid_t waitpid(pid_t pid, int *wstatus, int options);
Вся информация о завершении процесса влезает в тип данных int. Для получения кода возврата и причины завершения программы используются макросы, описанные в man-странице waitpid(2) .

Пример корректного завершения и получения кода возврата

#include #include #include #include #include int main() { int pid = fork(); switch(pid) { case -1: perror("fork"); return -1; case 0: // Child return 13; default: { // Parent int status; waitpid(pid, &status, 0); printf("exit normally? %s\n", (WIFEXITED(status) ? "true" : "false")); printf("child exitcode = %i\n", WEXITSTATUS(status)); break; } } return 0; }

$ gcc test.c && ./a.out exit normally? true child exitcode = 13


Пример некорректного завершения

Передача argv как NULL приводит к падению.

#include #include #include #include #include int main() { int pid = fork(); switch(pid) { case -1: perror("fork"); return -1; case 0: // Child execl("/bin/cat", NULL); return 13; default: { // Parent int status; waitpid(pid, &status, 0); if(WIFEXITED(status)) { printf("Exit normally with code %i\n", WEXITSTATUS(status)); } if(WIFSIGNALED(status)) { printf("killed with signal %i\n", WTERMSIG(status)); } break; } } return 0; }

$ gcc test.c && ./a.out killed with signal 6


Бывают случаи, при которых родитель завершается раньше, чем ребёнок. В таких случаях родителем ребёнка станет init и он применит вызов wait(2) , когда придёт время.

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

Благодарности

Спасибо Саше «Al» за редактуру и помощь в оформлении;

Спасибо Саше «Reisse» за понятные ответы на сложные вопросы.

Они стойко перенесли напавшее на меня вдохновение и напавший на них шквал моих вопросов.

Для просмотра запущенных процессов в Ubuntu Linux при помощи терминала, необходимо набрать в нем следующие команды:

top – команда выдачи данных об активности процессов в Ubuntu

Программа top динамически выдает в режиме реального времени информации о работающей системе, показывает запущенные процессы и потребление ими ресурсов системы. По умолчанию выдает задачи, наиболее загружающие процессор сервера, и обновляет список каждые пять секунд.
При выполнении top в верхней части окна отображается астрономическое время, время, прошедшее с момента запуска системы, число пользователей в системе, число запущенных процессов и число процессов, находящихся в разных состояниях, данные об использовании ЦПУ, памяти и свопа.
Далее идет таблица, характеризующая отдельные процессы. Число строк, отображаемых в этой таблице, определяется размером окна: сколько строк помещается, столько и выводится. Список процессов может быть отсортирован по используемому времени ЦПУ (по умолчанию), по использованию памяти, по PID, по времени исполнения. Переключать режимы отображения можно с помощью команд, которые программа top воспринимает. Это следующие команды (просто нажимайте соответствующие клавиши, только с учетом регистра, то есть вместе с клавишей Shift):
Shift+N — сортировка по PID;
Shift+A — сортировать процессы по возрасту;
Shift+P — сортировать процессы по использованию ЦПУ;
Shift+M — сортировать процессы по использованию памяти;
Shift+T — сортировка по времени выполнения.
Кроме команд, определяющих режим сортировки, команда top воспринимает еще ряд команд, которые позволяют управлять процессами в интерактивном режиме. С помощью команды можно завершить некоторый процесс (его PID будет запрошен), а с помощью команды можно переопределить значение nice для некоторого процесса. Таким образом, эти две команды аналогичны командам kill и renice .
Команду том можно использовать со следующими параметрами:
t – Включение и выключение выдачи на экран суммарных данных.
m – Включение и выключение выдачи на экран информации об использовании памяти.
A – Сортировка строк по максимальному потреблению различных системных ресурсов. Полезна для быстрой идентификации задач, для которых в системе не хватает ресурсов.
f – Вход в меню интерактивного конфигурирования данных, выдаваемых на экран командой top. Полезна для настройки команды top для выполнения специфической задачи.
o – Позволяет вам интерактивно задавать порядок строк, выдаваемой командой top.
r – Изменение приоритета процессов с помощью команды renice.
k – Удаление процесса с помощью команды kill.
z – Переключение между цветным / монохромным вариантом выдачи изображения.

ps – список процессов Ubuntu

Команда ps выдаст краткий список текущих процессов. Вывод команды ps схож с выводом команды top , однако он отображает статический снимок процессов. Для того, чтобы выбрать все процессы, используете параметр - A или - e

Вывод большего количества данных по процессам


ps -Al

Для того, чтобы включить выдачу всех данных (будут показаны аргументы командной строки, переданные в процесс):

ps -AlF


Вывод списка всех процессов Ubuntu


ps ax ps axu


Отображение потоков (LWP и NLWP)


ps -AlFH


Вывод информации о параметрах безопасности Ubuntu


ps -eo euser,ruser,suser,fuser ,f,comm ,label ps axZ ps -eM


Вывод дерева процессов


ps -ejH ps axjf pstree


Отображение потоков после процессов


ps -AlLm


Настраиваемая выдача данных


Позволяет выводить данные в последовательности, определяемой пользователем

ps -eo pid,tid,class,rtprio,ni,pri,psr,pcpu,stat ,wchan:14 ,comm ps axo stat ,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm ps -eopid,tt,user,fname,tmout,f,wchan


Вывод процессов, запущенных пользователем User


ps -U User -u User u


Вывод ID процессов, запущенных под apache


ps -C apache -o pid =


Вывод имени для PID 30470


ps -p 30470 -o comm =


Вывод 10 процессов, потребляющих наибольшее количество памяти


ps -auxf | sort -nr -k 4 | head -10


Вывод 10 процессов, потребляющих наибольший ресурс процессора


ps -auxf | sort -nr -k 3 | head -10

По умолчанию, команда ps выводит только информацию о процессах, запущенных в текущей сессии терминала bash. Для вывода информации по всем процессам необходимо ввести команду ps с параметром .
Для отображения желаемых полей необходимо ввести команду ps с параметром -о поле1,поле2,…, где через запятую перечисляются поля, которые необходимо отобразить.

free – использование памяти

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

free

uptime – сообщает, как долго работает система

Команду uptime можно использовать с тем, чтобы определить, как долго работает сервер. Выдаются: текущее время, сколько времени работает система, сколько в текущий момент зарегистрировано пользователей и какова средняя нагрузка на систему в последние 1, 5 и 15 минут.

uptime

w – определяем, кто зарегистрирован и что они делают

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

w username w User

pmap – использование процессами оперативной памяти

Команда pmap выдает данные о распределении памяти между процессами. Использование этой команды позволит найти причину узких мест, связанных с использованием памяти.

pmap -d PID

Для того, чтобы получить информацию об использовании памяти процессом с pid # 26321, введите:

pmap -d 26321

vmstat – активность системы, информация о системе и аппаратных ресурсах

Команда vmstat выдает информационный отчет об активности процессов, памяти, свопинга, поблочного ввода/вывода, прерываний и процессора.

vmstat 3


Выдача статистики использования памяти


vmstat -m


Получение данных об активности / неактивности страниц памяти


vmstat –a

mpstat – использование мультипроцессора

Команда mpstat выводит данные об активности каждого имеющегося в наличие процессора, процессор 0 будет первым. Команда mpstat -P ALL выводит данные о среднем использовании ресурсов для каждого из процессоров:
sa/ sa24 | more

С помощью команды sar Вы можете также получать данные в режиме реального времени:

sar 4 5

dstat

который выдает столько же данных, как вместе взятые vmstat, iostat, ifstat и netstat,
В Ubuntu не установлена. Для установки наберите в терминале:

sudo apt-get install dstat

Conky

- средство мониторинга, предназначенное для использования в X Window. Оно хорошо конфигурируемое и позволяет следить за многими системными переменными, в том числе состоянием процессора, памяти, пространства свопинга, дисковыми носителями, температурой, процессами, сетевыми интерфейсами, зарядом батареи, системными сообщениями, поступающими письмами и т.д.

GKrellM

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

htop

- улучшенная версия интерактивного просмотрщика процессов top. htop позволяет просматривать процессы в виде дерева процессов.

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

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

В этой статье будет затронута обширная тема, мы рассмотрим такие возможности:

  • Просмотр запущенных процессов
  • Просмотр информации о процессах
  • Поиск процессов в Linux
  • Изменение приоритета процессов
  • Завершение процессов
  • Ограничение памяти доступной процессу

Я не мог не включить в статью первые пункты, но они очень просты и мы не будем разбирать их очень подробно. Но вот все остальное может показаться сложным и недостаточно описанным.

Начнем с того, что разберемся в терминах. По сути, процесс - это каждая программа. Как я уже говорил для каждой запускаемой программы создается отдельный процесс. В рамках процесса программе выделяется процессорное время, оперативная память и другие системные ресурсы. У каждого процесса есть свой идентификатор, Proccess ID или просто PID, по ним, чаще всего и определяются процессы Linux. PID определяется неслучайно, как я уже говорил, программа инициализации получает PID 1, а каждая следующая запущенная программа - на единицу больше. Таким образом PID пользовательских программ доходит уже до нескольких тысяч.

На самом деле, процессы Linux не настолько абстрактны, какими они вам сейчас кажутся. Их вполне можно попытаться пощупать. Откройте ваш файловый менеджер, перейдите в корневой каталог, затем откройте папку /proc. Видите здесь кучу номеров? Так вот это все - PID всех запущенных процессов. В каждой из этих папок находится вся информация о процессе.

Например, посмотрим папку процесса 1. В папке есть другие под каталоги и много файлов. Файл cmdline содержит информацию о команде запуска процесса:

cat /proc/1/cmdline

/usr/lib/systemd/systemd

Поскольку у меня используется система инициализации Systemd, то и первый процесс запускается для нее. С помощью каталога /proc можно сделать все. Но это очень неудобно, особенно учитывая количество запущенных процессов в системе. Поэтому для реализации нужных задач существуют специальные утилиты. Перейдем к рассмотрению утилит, которые позволяют реализовать управление процессами в Linux.

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

В Linux есть очень большое количество утилит для решения различных задач по управлению процессами. Это и такие многофункциональные решения, как htop, top, а также простые утилиты, например, ps, kill, killall, who и т д. Я не буду рассматривать в этой статье графические утилиты, и top тоже рассматривать не буду. Первое потому что слишком просто, второе - потому что htop лучше. Мы остановимся на работе с программой htop и ее аналогами в форме утилит в стиле GNU, одна утилита - одна функция.

Давайте установим htop, если она у вас еще не установлена. В Ubuntu это делается так:

sudo apt install htop

В других дистрибутивах вам нужно просто использовать свой менеджер пакетов. Имя пакета такое же.

Посмотреть запущенные процессы

Это очень простая задача, и также просто она решается. Для этого существует множество утилит, начиная от обычной ps, до более продвинутых интерактивных top, htop и так далее.

Открыв htop, мы сразу видим список запущенных процессов. Конечно, здесь отображены не все процессы linux, их-то в системе очень много, вы уже знаете, все они на один экран не поместятся. По умолчанию выводятся процессы, запущенные от имени вашего пользователя:

Вы можете увидеть такую информацию о процессе:

  • PID - идентификатор процесса
  • USER - пользователь, от которого был запущен процесс
  • PRI - приоритет процесса linux на уровне ядра (обычно NI+20)
  • NI - приоритет выполнения процесса от -20 до 19
  • S - состояние процесса
  • CPU - используемые ресурсы процессора
  • MEM - использованная память
  • TIME - время работы процесса

К отображению можно добавить и дополнительные параметры, но эти главные. Добавить параметры можно с помощью меню Setup. Там все очень просто, читайте подсказки и следуйте указаниям. Например, добавлен параметр PPID:

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

Также есть интересная возможность разместить процессы в виде дерева. Вы сможете увидеть, каким процессом был запущен тот или иной процесс. Для отображения дерева нажмите кнопку F5:

Почти те же действия вы можете выполнять с помощью программы ps. Только здесь нет такого удобного интерактивного режима. Все делается с помощью опций.

Рассмотрим основные опции, которые будем использовать:

  • -e - вывести информацию обо всех процессах
  • -a - вывести информацию обо всех наиболее часто запрашиваемых процессах
  • -t - показывать только процессы из этого терминала
  • -p - показывать информацию только об указанном процессе
  • -u - показывать процессы только определенного пользователя

Одним словом, чтобы посмотреть все активные на данный момент процессы в linux, используется сочетание опций aux:

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

ps aux --sort=%mem

Список будет отсортирован в обратном порядке, внизу значения больше, вверху - меньше. Если нужно в обратном порядке, добавьте минус:

ps aux --sort=-%cpu

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

Казалось бы, у ps нет возможности стоить деревья процессов. Но не совсем, для этого существует отдельная команда:

Поиск процессов в Linux

Список процессов, это хорошо. Но иногда, когда какой-нибудь процесс завис и нужно убить процесс Linux или нам нужно провести с ним какие-либо действия, нужно выделить этот процесс из списка, узнать его PID и информацию о нем.

Чтобы найти процесс linux в htop можно использовать кнопку F3. Нажмите F3 и наберите нужное слово. Дальше чтобы перейти к следующему вхождению нажимайте F2 или Esc для завершения поиска:

Для поиска процессов в htop можно использовать также фильтр htop. Нажмите F4, введите слово и будут выведены только процессы linux, имя которых включает это слово.

В утилите ps фильтрации нет, но зато мы можем использовать утилиту grep, перенаправив вывод ps на нее чтобы найти процесс linux:

ps aux | grep chromium

Это очень часто употребляемая команда.

Изменение приоритета процессов

Приоритет процесса linux означает, насколько больше процессорного времени будет отдано этому процессу по сравнению с другими. Так мы можем очень тонко настроить какая программа будет работать быстрее, а какая медленнее. Значение приоритета может колебаться от 19 (минимальный приоритет) до -20 - максимальный приоритет процесса linux. Причем, уменьшать приоритет можно с правами обычного пользователя, но чтобы его увеличить нужны права суперпользователя.

В htop для управления приоритетом используется параметр Nice. Напомню, что Priv, это всего лишь поправка, она в большинстве случаев больше за Nice на 20. Чтобы изменить приоритет процесса просто установите на него курсор и нажимайте F7 для уменьшения числа (увеличения приоритета) или F8 - для увеличения числа.

Но и для решения этой задачи управления процессами Linux необязательно использовать htop. Вы можете сделать все и другими командами. Например, команда nice. С помощью нее вы можете указать приоритет для запускаемого процесса:

nice -n 10 apt-get upgrade

Или изменить приоритет для уже существующего по его pid:

renice -n 10 -p 1343

Завершение процессов в Linux

Если процесс завис и не отвечает, его необходимо завершить. В htop, чтобы убить процесс Linux, просто установите курсор на процесс и нажмите F9:

Система для управления процессами использует определенные сигналы, есть сигналы, которые указывают процессу завершиться. Вот несколько основных сигналов:

  • SIGKILL - попросить процесс сохранить данные и завершится
  • SIGTERM - завершить процесс немедленно, без сохранения

Вообще сигналов есть несколько десятков, но мы не будем их рассматривать. Отправим сигнал SIGKILL:

Также можно воспользоваться утилитой kill:

Также можно уничтожить процесс по имени:

killall chromium

Ограничение процессов

Управление процессами в Linux позволяет контролировать практически все. Вы уже видели что можно сделать, но можно еще больше. С помощью команды ulimit и конфигурационного файла /etc/security/limits.conf вы можете ограничить процессам доступ к системным ресурсам, таким как память, файлы и процессор. Например, вы можете ограничить память процесса Linux, количество файлов и т д.

Запись в файле имеет следующий вид:

<домен> <тип> <элемент> <значение>

  • домен - имя пользователя, группы или UID
  • тип - вид ограничений - soft или hard
  • элемент - ресурс который будет ограничен
  • значение - необходимый предел

Жесткие ограничения устанавливаются суперпользователем и не могут быть изменены обычными пользователями. Мягкие, soft ограничения могут меняться пользователями с помощью команды ulimit.

Рассмотрим основные ограничения, которые можно применить к процессам:

  • nofile
  • as - максимальное количество оперативной памяти
  • stack - максимальный размер стека
  • cpu - максимальное процессорное время
  • nproc - максимальное количество ядер процессора
  • locks - количество заблокированных файлов
  • nice - максимальный приоритет процесса

Например, ограничим процессорное время для процессов пользователя sergiy:

sergiy hard nproc 20

Посмотреть ограничения для определенного процесса вы можете в папке proc:

cat /proc/PID/limits

Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 204800 unlimited bytes
Max core file size 0 unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 23562 23562 processes
Max open files 1024 4096 files
Max locked memory 18446744073708503040 18446744073708503040 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 23562 23562 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 0 0
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us

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

Вот опции команды:

  • -S - мягкое ограничение
  • -H - жесткое ограничение
  • -a - вывести всю информацию
  • -f - максимальный размер создаваемых файлов
  • -n - максимальное количество открытых файлов
  • -s - максимальный размер стека
  • -t - максимальное количество процессорного времени
  • -u - максимальное количество запущенных процессов
  • -v - максимальный объем виртуальной памяти

Например, мы можем установить новое ограничение для количества открываемых файлов:

Теперь смотрим:

Установим лимит оперативной памяти:

ulimit -Sv 500000

Напоминаю, что это ограничение будет актуально для всех программ, выполняемых в этом терминале.

Выводы

Вот и все. Теперь управление процессами в Linux не вызовет у вас проблем. Мы рассмотрели очень даже подробно эту тему. Если у вас остались вопросы или есть предложения по дополнению статьи, пишите в комментариях!

В этом отрывке рассмотрены команды управления процессами. Вы научитесь замораживать процессы, размораживать, отправлять в фоновый режим, изменять приоритет, просматривать запущенные процессы и жестоко их убивать. Введено понятие сигналов. Рассмотрены такие команды, как bg, fg, jobs, kill, nohup, nice, renice, ps и top.

Об авторах

Daniel Robbins

Дэниэль Роббинс - основатель сообщества Gentoo и создатель операционной системы Gentoo Linux. Дэниэль проживает в Нью-Мехико со свой женой Мэри и двумя энергичными дочерьми. Он также основатель и глава Funtoo , написал множество технических статей для IBM developerWorks , Intel Developer Services и C/C++ Users Journal.

Chris Houser

Крис Хаусер был сторонником UNIX c 1994 года, когда присоединился к команде администраторов университета Тэйлора (Индиана, США), где получил степень бакалавра в компьютерных науках и математике. После он работал во множестве областей, включая веб-приложения, редактирование видео, драйвера для UNIX и криптографическую защиту. В настоящий момент работает в Sentry Data Systems. Крис также сделал вклад во множество свободных проектов, таких как Gentoo Linux и Clojure, стал соавтором книги The Joy of Clojure .

Aron Griffis

Эйрон Гриффис живет на территории Бостона, где провел последнее десятилетие работая в Hewlett-Packard над такими проектами, как сетевые UNIX-драйвера для Tru64, сертификация безопасности Linux, Xen и KVM виртуализация, и самое последнее - платформа HP ePrint . В свободное от программирования время Эйрон предпочитает размыщлять над проблемами программирования катаясь на своем велосипеде, жонглируя битами, или болея за бостонскую профессиональную бейсбольную команду «Красные Носки».

В сегодняшнем посте расскажу о том, как работают процессы в ОC Linux , а так же как управлять этими самыми процессами , о выполнении процессов в фоне, о повышении/понижении приоритета процессов.

В общем представлении, процесс - это программа, выполняющаяся в оперативной памяти компьютера. Реально, все гораздо сложней.

В многозадачной системе может быть запущено множество программ. Каждая программа может запустить множество процессов (читай: подпрограмм). При этом в единственный момент на машине, выполняется только 1 процесс. То есть в единственный момент времени ресурсы железа (процессорное время, память, порт ввода/вывода ) может использоваться только единственным процессом. Очередью, в которой процессу выделяется определенный ресурс железа, управляет планировщик. При этом, во время прерывания одного процесса и запуска (возобновления) другого процесса, состояние процесса (выполняемые действия, на каком этапе процесс приостановлен) запоминается и записывается в область памяти. Планировщик в Linux - это часть ядра, отвечающая за указанную функциональность. В задачи планировщика так же входит отслеживание и выделение запускаемым процессам определенного приоритета, чтобы процессы "не мешали" друг-другу работать, а так же распределение пространства памяти, чтобы пространство памяти одного процесса не пересекалось с пространством другого.

Все новые процессы в Linux порождаются клонированием какого-то уже имеющегося процесса, с помощью вызова системных функций clone(2) и fork(2) (от forking - порождение). У нового (порожденного или дочернего) процесса тоже окружение, что и у родителя, отличается только номер ID процесса (т.н. PID). Жизнь типичного процесса в Linux можно представить следующей схемой:

На которой можно описать пошагово следующие этапы:

  • процесс /bin/bash клонирует себя системным вызовом fork()
  • при этом создается клон /bin/bash с новым PID (идентификатор процесса) и PPID - равный PID родителя
  • Клон выполняет системный вызов exec с указанием на исполняемый файл и заменяет свой код - кодом исполняемого файла (родительский процесс при этом ждет завершения потомка - wait)
    • при этом, если по каком-то причинам, потомок завершил свою работу, а родительский процесс не смог получить об этом сигнал, то данный процесс (потомок) не освобождает занятые структуры ядра и состояние процесса становиться - zombie. О состояниях процесса ниже...

Очень наглядную схему предоставила википедия:

Из вышесказанного может последовать логичный вопрос: если новый процесс - всегда копия существующего, то каким образом в системе берется самый первый из процессов?

Первый процесс в системе запускается при инициализации ядра. Данный процесс называется - init и имеет PID=1. Это прородитель всех процессов в системе.

В каких же состояниях может находиться процесс в Linux?

Каждый запущенный процесс в любой момент времени находится в одном из следующих состояний (которое называют еще статусом процесса):

  • Активен (R=Running) – процесс находится в очереди на выполнение, то есть либо выполняется в данный момент, либо ожидает выделения ему очередного кванта времени центрального процессора.
  • «Спит» (S=Sleeping) – процесс находится в состоянии прерываемого ожидания, то есть ожидает какого-то события, сигнала или освобождения нужного ресурса.
  • Находится в состоянии непрерываемого ожидания (D=Direct) – процесс ожидает определенного («прямого») сигнала от аппаратной части и не реагирует на другие сигналы;
  • Приостановлен (T) – процесс находится в режиме трассировки (обычно такое состояние возникает при отладке программ).
  • «Зомби» (Z=Zombie) – это процесс, выполнение которого завершилось, но относящиеся к нему структуры ядра по каким-то причинам не освобождены. Одной из причин их появления в системе может быть следующая ситуация. Обычно освобождение структур ядра, относящихся к процессу, выполняет процесс-родитель после получения от потомка сигнала о завершении. Но бывают случаи, когда родительский процесс завершается раньше дочернего. Процессы, не имеющие родителя, называются "сиротами ". "Сироты " автоматически усыновляются процессом init , который и принимает сигналы об их завершении. Если процесс-родитель или init по каким-то причинам не может принять сигнал о завершении дочернего процесса, то процесс-потомок превращается в "зомби" и получает статус Z. Процессы-зомби не занимают процессорного времени (т. е. их выполнение прекращается), но соответствующие им структуры ядра не освобождаются. В некотором смысле это «мертвые» процессы. Уничтожение таких процессов - одна из обязанностей системного администратора. Хочу отметить, что появление данных процессов говорит о том, что в системе что-то не в порядке, и скорее всего не в порядке с аппаратной частью, так что берем memtest и MHDD и тестим-тестим. Не исключен вариант и кривого кода программы.

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

Т.к. в большинстве случаев, демоны в Linux простаивают и ожидают поступления каких-либо данных, соответственно, нужны относительно редко, так что держать их в памяти постоянно загруженными и расходовать на это ресурсы системы нерационально. Для организации работы демонов придуман демон inetd или его более защищенная модификация xinetd (eX tended I nterNET Daemon или расширенный Интернет демон). В функции inetd (Xinetd) можно выделить:

  • установить ограничение на количество запускаемых серверов (служб , демонов)
  • наблюдение за соединениями на определенных портах и обработка входящих запросов
  • ограничение доступа к сервисам на основе ACL (списков контроля доступа)

Все процессы в системе, не важно Linux это или другая ОС, обмениваются между собой какой-либо информацией. Отсюда можно задать вопрос, а как же происходит межПРОЦЕССный обмен?

В ОС LINUX существует несколько видов можпроцессного обмена, а точнее сказать средств межпроцессного взаимодействия (Interprocess Communication - IPC) , которые можно разбить на несколько уровней:

локальный (привязаны к процессору и возможны только в пределах компьютера);

-- каналы

  1. pipe (они же конвейеры, так же неименованные каналы), о них я много рассказывал в прошлом посте, примером можно привести: команда1 | команда2. По сути, pipe использует stdin, stdout и stderr.
  2. Именованные каналы (FIFO: First In First Out). Данный вид канала создаётся с помощью mknod или mkfifo , и два различных процесса могут обратиться к нему по имени. Пример работы с fifo:

в первом терминале (создаем именованный канал в виде файла pipe и из канала направляем данные с помощью конвейера в архиватор):

# mkfifo pipe # ls -l total 0 prw-r--r-- 1 root root 0 Nov 9 19:41 pipe # gzip -9 -c < pipe > out

во втором терминале (отправляем в именованный канал данные):

# cat /path/to/file > pipe

в результате это приведет к сжатию передаваемых данных gzip-ом

-- сигналы

  • с терминала, нажатием специальных клавиш или комбинаций (например, нажатие Ctrl-C генерирует SIGINT, а Ctrl-Z SIGTSTP);
  • ядром системы:
    • при возникновении аппаратных исключений (недопустимых инструкций, нарушениях при обращении в память, системных сбоях и т. п.);
    • ошибочных системных вызовах;
    • для информирования о событиях ввода-вывода;
  • одним процессом другому (или самому себе), с помощью системного вызова kill(), в том числе:
    • из шелла, утилитой /bin/kill .

сигнал - это асинхронное уведомление процесса о каком-либо событии. Когда сигнал послан процессу, операционная система прерывает выполнение процесса. Если процесс установил собственный обработчик сигнала, операционная система запускает этот обработчик, передав ему информацию о сигнале. Если процесс не установил обработчик, то выполняется обработчик по умолчанию.
Все сигналы начинаются на «SIG…» и имеют числовые соответствия, определяемые в заголовочном файле signal.h. Числовые значения сигналов могут меняться от системы к системе, хотя основная их часть имеет в разных системах одни и те же значения. Утилита kill позволяет задавать сигнал как числом, так и символьным обозначением.
Сигналы можно послать следующими способами:

-- разделяемая память

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

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

-- очереди сообщений

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

удаленный;

-- удаленные вызовы процедур (Remote Procedure Calls - RPC)

RPC - разновидность технологий, которая позволяет компьютерным программам вызывать функции или процедуры в другом адресном пространстве (как правило, на удалённых компьютерах). Обычно, реализация RPC технологии включает в себя два компонента: сетевой протокол (чаще TCP и UDP, реже HTTP) для обмена в режиме клиент-сервер и язык сериализации объектов (или структур, для необъектных RPC).

-- сокеты Unix

Сокеты UNIX бывают 2х типов: локальные и сетевые . При использовании локального сокета , ему присваивается UNIX-адрес и просто будет создан специальный файл (файл сокета ) по заданному пути, через который смогут сообщаться любые локальные процессы путём простого чтения/записи из него. Сокеты представляют собой виртуальный объект, который существует, пока на него ссылается хотя бы один из процессов. При использовании сетевого сокета , создается абстрактный объект привязанный к слушающему порту операционной системы и сетевому интерфейсу, ему присваивается INET-адрес , который имеет адрес интерфейса и слушающего порта.

высокоуровневый

  1. Обычно - пакеты программного обеспечения, которые реализуют промежуточный слой между системной платформой и приложением. Эти пакеты предназначены для переноса уже испытанных протоколов коммуникации приложения на более новую архитектуру. Примером можно привести: DIPC, MPI и др. (мне не знакомы, честно говоря)

Итак. Подведем маленький итог:

  • В Linux есть процессы,
  • каждый процесс может запускать подпроцессы (нити),
  • создание нового процесса создается клонированием исходного,
  • прородителем всех процессов в системе является процесс init, запускаемый ядром системы при загрузке.
  • процессы взаимодействуют между собой по средствам можпроцессного взаимодействия:
    • каналы
    • сигналы
    • сокеты
    • разделяемая память
  • каждый процесс обладает свойствами (читай: обладает следующим контекстом):
    • PID - идентификатор процесса
    • PPID - идентификатор процесса, породившего данный
    • UID и GID - идентификаторы прав процесса (соответствует UID и GID пользователя, от которого запущен процесс)
    • приоритет процесса
    • состояние процесса (выполнение, сон и т.п.)
    • так же у процесса есть таблица открытых (используемых) файлов

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

Получение информации о процессе

Перед тем как управлять процессами, нужно научиться получать о процессах необходимую информацию . В Linux существует псевдо procfs , которая в большинстве дистрибутивов монтируется в общую ФС в каталог /proc . У данной файловой системы нет физического места размещения, нет блочного устройства, такое как жесткий диск. Вся информация, хранимая в данном каталоге находится в оперативной памяти компьютера, контролируется ядром ОС и она не предназначена для хранения файлов пользователя. О структуре данного каталога я написал в статье . В этой файловой системе дано достаточно много информации, чтобы узнать о процессах и о системе в целом.

Но пользоваться данным каталогом очень не удобно, чтобы узнать о каком-либо процессе информацию, придется просмотреть кучу файлов и каталогов. Чтобы избавиться от ненужного труда, можно использовать существующие утилиты ps и top для просмотра информации о процессах.

Чтобы получить список всех процессов , достаточно ввести команду:

# ps aux

Прокомментируем некоторые интересные моменты. Можно заметить, что некоторые процессы указаны в квадратных скобках – это процессы, которые входят непосредственно в состав ядра и выполняют важные системные задачи, например, такие как управление буферным кэшем и организацией свопинга . С ними лучше не экспериментировать – ничего хорошего из этого не выйдет:). Остальная часть процессов относится к пользовательским.

Какую информацию можно получить по каждому процессу (комментарии к некоторым полям):

  • PID, PPID – идентификатор процесса и его родителя.
  • %CPU – доля процессорного времени, выделенная процессу.
  • %MEM – процент используемой оперативной памяти.
  • VSZ – виртуальный размер процесса.
  • TTY – управляющий терминал.
  • STAT – статус процесса:
    • R – выполняется;
    • S – спит;
    • Z – зомби;
    • < – Повышенный приоритет;
    • + – Находится в интерактивном режиме.
  • START – время запуска.
  • TIME – время исполнения на процессоре.

Команда ps делает моментальный снимок процессов в текущий момент. В отличии от нее, команда top - динамически выводит состояние процессов и их активность в реальном режиме времени.

Пример вывода команды top:

14:32:49 up 35 days, 6:01, 4 users, load average: 0.65, 0.51, 0.49 Tasks: 432 total, 1 running, 431 sleeping, 0 stopped, 0 zombie CPU0: 1.6%us, 3.6%sy, 0.0%ni, 85.3%id, 9.2%wa, 0.0%hi, 0.3%si, 0.0%st CPU1: 0.9%us, 1.9%sy, 0.0%ni, 96.9%id, 0.0%wa, 0.0%hi, 0.3%si, 0.0%st Mem: 1033596K total, 1016644K used, 16952K free, 82928K buffers Swap: 2096376K total, 12632K used, 2083744K free, 478220K cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2788 root 15 -5 0 0 0 S 2.0 0.0 404:43.97 md3_raid1 7961 root 20 0 5964 2528 1684 R 2.0 0.2 0:00.14 top 6629 root 20 0 8612 2884 2096 S 0.7 0.3 0:00.96 dovecot-auth 57 root 15 -5 0 0 0 S 0.3 0.0 4:36.10 kblockd/0 8703 ulogd 20 0 17700 4216 656 S 0.3 0.4 87:23.98 ulogd 11336 ldap 20 0 394M 15M 8292 S 0.3 1.5 5:29.28 slapd 25757 ldap 20 0 394M 15M 8292 S 0.3 1.5 5:11.71 slapd 10991 root 20 0 2188 1004 588 S 0.3 0.1 4:23.33 dovecot 1 root 20 0 1712 516 464 S 0.0 0.0 0:46.17 init 2 root 15 -5 0 0 0 S 0.0 0.0 0:00.00 kthreadd 3 root RT -5 0 0 0 S 0.0 0.0 0:05.92 migration/0 ..... 2960 root 16 -4 1980 520 392 S 0.0 0.1 0:10.04 udevd 2993 dovecot 20 0 4412 1800 1476 S 0.0 0.2 0:00.00 pop3-login 2994 dovecot 20 0 4412 1800 1476 S 0.0 0.2 0:00.02 pop3-login

В верхней части вывода отображается астрономическое время, время, прошедшее с момента запуска системы, число пользователей в системе, число запущенных процессов и число процессов, находящихся в разных состояниях, данные об использовании ЦПУ, памяти и свопа. А далее идет таблица, характеризующая отдельные процессы. Число строк, отображаемых в этой таблице, определяется размером окна: сколько строк помещается, столько и выводится.

Содержимое окна обновляется каждые 5 секунд. Список процессов может быть отсортирован по используемому времени ЦПУ (по умолчанию), по использованию памяти, по PID, по времени исполнения. Переключать режимы отображения можно с помощью следующих клавиатурных команд:

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

Полезную информацию, так же, позволяет получить программа lsof, которая выдает список всех файлов, используемых сейчас процессами, включая каталоги, занятые потому, что какой-либо процесс использует их в качестве текущего или корневого; разделяемые библиотеки, загруженные в память; и т. д.

Итак, теперь об управлении процессами .

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

Каждому процессу при запуске устанавливается определенный приоритет , который имеет значение от -20 до +20, где +20 - самый низкий. Приоритет нового процесса равен приоритету процесса-родителя. Для изменения приоритета запускаемой программы существует утилита nice . Пример ее использования:

# nice [- adnice] command

где adnice - значение (от –20 до +19), добавляемое к значению nice процесса-родителя. Отрицательные значения может устанавливать только суперпользователь. Если опция adnice не задана, то по умолчанию для процесса-потомка устанавливается значение nice, увеличенное на 10 по сравнению со значением nice родительского процесса.

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

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

# kill [-SIG] PID

где SIG - это номер сигнала или наименование сигнала, причем если указание сигнала опущено, то посылается сигнал 15 (SIGTERM - программное завершение процесса). Часто используется сигнал 9 (KILL ), с помощью которого суперпользователь может завершить любой процесс. Но сигнал этот очень "грубый", если можно так выразиться, потому что он просто «убивает» процесс, не давая ему времени на корректное сохранение всех обработанных данных. Поэтому в большинстве случаев рекомендуется использовать сигналы TERM или QUIT , которые завершают процесс более "мягко". Если процессу необходимо как-то по-особенному реагировать на сигнал, он может зарегистрировать обработчик , а если обработчика нет, за него отреагирует система.

Два сигнала – 9 (KILL ) и 19 (STOP ) – всегда обрабатывает система . Первый из них нужен для того, чтобы убить процесс наверняка (отсюда и название). Сигнал STOP приостанавливает процесс: в таком состояниипроцесс не удаляется из таблицы процессов, но и не выполняется до тех пор, пока не получит сигнал 18 (CONT) – после чего продолжит работу. В Linux сигнал STOP можно передать активному процессу с помощью управляющего символа " ^Z ".

Обычные пользователи могут посылать сигналы только тем процессам, для которых они являются владельцами. Если в команде kill воспользоваться идентификатором процесса (PID), равным -1, то указанный в команде сигнал будет послан всем принадлежащим данному пользователю процессам. Суперпользователь root может посылать сигналы любым процессам. Когда суперпользователь посылает сигнал идентификатору -1, он рассылается всем процессам, за исключением системных. Если этим сигналом будет SIGKILL, то у простых пользователей будут потеряны все открытые ими, но не сохраненные файлы данных.

При обычном запуске процесс работает на переднем плане. то есть процесс "привязывается" к терминалу, с которого он запущен, воспринимая ввод с этого терминала и осуществляя на него вывод. Но можно запустить процесс в фоновом режиме, когда он не связан с терминалом, для чего в конце командной строки запуска программы добавляют символ &.

В имеются две встроенные команды, которые служат для перевода процессов на передний план или возврата их в фоновый режим. Команда fg переводит указанный в аргументе процесс на передний план, а команда bg - переводит процесс в фоновый режим. Одной командой bg можно перевести в фоновый режим сразу несколько процессов, а вот возвращать их на передний план необходимо по одному. Аргументами команд fg и bg могут являться только номера заданий, запущенных из текущего экземпляра shell. Возможные значения заданий можно увидеть, выполнив команду jobs .

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

# nohup команда &

Запущенный таким образом процесс будет игнорировать посылаемые ему сигналы (не игнорируются только сигналы SIGHUP и SIGQUIT ). Хочу так же выделить команду pstree , которая показывает дерево процессов. Очень наглядно, кстати.