Invest-currency.ru

Как обезопасить себя в кризис?
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Дочерние процессы linux

Все, что вам нужно знать о процессах в Linux

Оригинал: All You Need To Know About Processes in Linux [Comprehensive Guide]
Автор: Aaron Kili
Дата публикации: 31 марта 2017 года
Перевод: А. Кривошей
Дата перевода: август 2017 г.

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

Типы процессов

В Linux есть два основных типа процессов:

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

Что такое демоны

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

Создание процессов в Linux

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

Есть два распространенных способа создания нового процесса в Linux:

1. С помощью функции System(). Этот способ сравнительно прост, однако неэффективен и создает определенные риски с точки зрения безопасности.
2. С помощью функций fork() и exec() — более продвинутая техника с точки зрения гибкости, скорости и безопасности.

Как Linux идентифицирует процессы?

Поскольку Linux — многопользовательская система, и различные пользователи могут одновременно запускать разные программы, каждый запущенный экземпляр программы должен получать уникальный идентификатор от ядра системы.
Программы идентифицируются по ID процесса (PID), а также по ID родительского процесса (PPID), поэтому процессы можно разделить на следующие категории:

Родительские процессы — это процессы, которые в процессе работы создают другие процессы.
Дочерние процессы — это процессы, созданные другими процессами.

Процесс Init

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

Процесс Init всегда получает ID 1. Он функционирует как приемный родитель для всех осиротевших процессов.

Для определения ID процесса можно использовать команду pidof:

Найти ID процесса и ID родительского процесса для системной оболочки можно с помощью команд:

Запуск процессов в Linux

При старте команды или программы (например cloudcmd – CloudCommander), она запускает процесс в системе. Вы можете запустить процесс переднего плана (интерактивный), как показано ниже, он подключится к терминалу и пользователь сможет взаимодействовать с ним:

Фоновые процессы в Linux

Для запуска фонового процесса (неинтерактивного) используется символ &, при этом процесс не сможет читать ввод от пользователя, пока не будет перемещен на передний план.

Вы также можете отправить процесс на задний план, приостановив его с помощью [Ctrl + Z], это отправит сигнал SIGSTOP процессу, тем самым прекратив его работу; он простаивает:

Для продолжения выполнения приостановленного в фоне процесса, используется команда bg:

Для перевода процесса из фонового режима на передний план используется команда fg вместе с ID:

Состояние процесса в Linux

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

Running (работа) — процесс работает (он является текущим процессом в системе) или готов к работе (ждет выделения ресурсов процессора).
Waiting (ожидание) — в этом состоянии процесс ждет события, которое должно запустить его, или выделения системных ресурсов.
Кроме того, ядро системы делит процессы в состоянии ожидания на два типа: перываемые процессы, состояние ожидания которых может быть прервано сигналом, и непрерываемые, состояние ожидания которых может быть прервано только аппаратным способом.
Stopped (остановка) — в этом состоянии процесс останавливает работу, обычно после получения соответствующего сигнала. Например, процесс может быть остановлен для отладки.
Zombie (зомби) — процесс мертв, то есть он был остановлен, но в системе осталась выполняемая им задача.

Как просмотреть активные процессы в Linux

В Linux есть несколько утилит для просмотра запущенных в системе процессов, наиболее широко известны команды ps и top:

1. Команда ps

Она выводит информацию о выбранных активных процессах, как показано ниже.

2. top – утилита системного мониторинга

top — это мощная утилита, которая позволяет в режиме реального времени просматривать список запущенных процессов, как показано ниже:

3. glances – утилита системного мониторинга

glances — это сравнительно новая утилита для мониторинга активности системы с продвинутыми возможностями:

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

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

В Linux также имеются команды для управления процессами, например kill, pkill, pgrep и killall. Ниже приведено несколько примеров их использования:

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

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

Отправка сигналов процессу

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

Для отправки сигналов процессу используются описанные выше команды kill, pkill или pgrep. Однако программа ответит на сигнал, только если она запрограммирована распознавать такой сигнал.

Большинство сигналов предназначены для использования системой или программистами при написании кода. Следующие сигналы могут быть полезны пользователю:

SIGHUP 1 – отправляется процессу при закрытии контролирующего его терминала.
SIGINT 2 – отправляется процессу контролирующим его терминалом, если пользователь прерывает работу процесса клавишами [Ctrl+C].
SIGQUIT 3 – отправляется процессу, если пользователь посылает сигнал выхода из программы [Ctrl+D].
SIGKILL 9 – этот сигнал немедленно завершает (убивает) процесс без выполнения любых операций очистки файлов, логов и т.д.
SIGTERM 15 – это сигнал завершения работы программы (он по умоланию отправляется командой kill).
SIGTSTP 20 – отправляется процессу контролирующим его терминалом с запросом на остановку (terminal stop); инициируется при нажатии [Ctrl+Z].

Ниже приведены примеры использования команд kill для завершения работы Firefox при его зависании с использованием PID:

Для завершения программы с использованием ее названия используются команды pkill или killall:

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

В Linux все активные процессы имеют определенное значение приоритета (nice). Процессы с более высоким приоритетом обычно получают больше процессорного времени, чем процессы с более низким приоритетом.

Однако пользователь с привилегиями root может менять приоритет с помощью команд nice и renice.
В выводе команды top столбец NI отображает значения nice для процессов.

Вы можете использовать команду nice, чтобы задать значение nice процесса. Не забывайте, что обычный пользователь может присвоить процессу значение nice от 0 до 20, только если это процесс ему принадлежит.
Отрицательные значения nice может использовать только пользователь root.

Для понижения приоритета процесса используется команда renice:

Другие статьи об управлении процессами в Linux вы найдете на странице «Процессы в Linux-системе».

Дочерние процессы linux

Сухая формулировка говорит нам что процесс это — совокупность программного кода и данных, загруженных в память ЭВМ. На первый взгляд процесс — это запущенная программа (приложение) или команда. Но это не совсем так. Некоторые приложения могут создавать несколько процессов одновременно.

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

Работающий процесс — в данный момент код процесса выполняется.

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

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

Каждому процессу в системе назначаются числовые идентификаторы (личные номера) в диапазоне от 1 до 65535 (PID — Process Identifier — идентификатор процесса) и идентификаторы родительского процесса (PPID — Parent Process Identifier — идентификатор родительского процесса). PID является именем процесса, по которому мы можем адресовать процесс в операционной системе при использовании различных средств просмотра и управления процессами. PPID определяет родственные отношения между процессами, которые в значительной степени определяют его свойства и возможности. Другие параметры, которые необходимы для работы программы, называют «окружение процесса». Одним из таких параметров является управляющий терминал — имя терминального устройства, на которое процесс выводит информацию и с которого информацию получает. Управляющий терминал имеют далеко не все процессы. Процессы, не привязанные к какому-то конкретному терминалу называются «демонами» (daemons). Такие процессы, будучи запущенными пользователем, не завершают свою работу по окончании сеанса, а продолжают работать, так как они не связаны никак с текущим сеансом и не могут быть автоматически завершены. Как правило, с помощью демонов реализуются серверные службы, так например сервер печати реализован процессом-демоном cupsd, а сервер журналирования — syslogd.

Для просмотра списка процессов в Linux существует команда ps. Формат команды следующий:

ps [PID] [options] — просмотр списка процессов. Без параметров ps показывает все процессы, которы были запущены в течение текущей сессии, за исключением демонов. Options может принимать одно из следующих значений или их комбинации:

-а или -e — показать все процессы

-f — полный листинг

-w — показать полные строки описания процессов. Если они превосходят
длину экрана, то перенести описание на следующую строку.

Это далеко не все параметры команды ps. Остальные параметры Вы можете узнать, просто набрав man ps.

Пример1:

[gserg@WEBMEDIA gserg]$ ps

PID TTY TIME CMD

3126 pts/2 00:00:00 bash

3158 pts/2 00:00:00 ps

Пример2:

[gserg@WEBMEDIA gserg]$ ps 3126

PID TTY STAT TIME COMMAND

3126 pts/2 S 0:00 /bin/bash

Пример3:

[gserg@WEBMEDIA gserg]$ ps -ef

UID PID PPID C STIME TTY TIME CMD

root 1 0 0 10:01 ? 00:00:03 init [5]

root 2 1 0 10:01 ? 00:00:00 [keventd]

Читать еще:  Ускорение телефона 4pda

root 3 1 0 10:01 ? 00:00:00 [kapmd]

root 4 1 0 10:01 ? 00:00:00 [ksoftirqd_CPU0]

root 5 1 0 10:01 ? 00:00:24 [kswapd]

root 6 1 0 10:01 ? 00:00:00 [bdflush]

gserg 3126 3124 0 17:56 pts/2 00:00:00 /bin/bash

gserg 3160 3126 0 17:59 pts/2 00:00:00 ps -ef

Пример4:

[gserg@WEBMEDIA gserg]$ ps -efw

UID PID PPID C STIME TTY TIME CMD

root 1 0 0 10:01 ? 00:00:03 init [5]

root 2 1 0 10:01 ? 00:00:00 [keventd]

root 3 1 0 10:01 ? 00:00:00 [kapmd]

root 4 1 0 10:01 ? 00:00:00 [ksoftirqd_CPU0]

root 5 1 0 10:01 ? 00:00:24 [kswapd]

root 1130 1 0 10:02 ? 00:00:00 /usr/sbin/apmd -p 10 -w 5 -W -P /etc/sysconfig/apm-scripts/apmd_proxy

gserg 3172 3126 0 18:01 pts/2 00:00:00 ps -efw

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

На самом деле операционная система воспринимает работающего в ней пользователя как набор запущенных от его имени процессов. Ведь и сам сеанс пользователя открывается в командной оболочке (или оболочке Х) от имени пользователя. Поэтому когда мы говорим «права доступа пользователя к файлу» то подразумеваем «права доступа процессов, запущенных от имени пользователя к файлу».

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

Как правило, реальные и эффективные идентификаторы процессов одинаковые, но есть и исключения. Например, для работы утилиты passwd необходимо использовать идентификатор суперпользователя, так как только суперпользователь имеет права на запись в файлы паролей. В этом случае эффективные идентификаторы процесса будут отличаться от реальных. Возникает резонный вопрос — как это было реализовано?

У каждого файла есть набор специальных прав доступа — биты SUID и SGID. Эти биты позволяют при запуске программы присвоить ей эффективные идентификаторы владельца и группы-владельца соответственно и выполнять процесс с правами доступа другого пользователя. Так как файл passwd принадлежит пользователю root и у него установлен бит SUID, то при запуске процесс passwd будет обладать правами пользователя root.

Устанавливаются биты SGID и SUID командой chmod:

chmod u+s filename — установка бита SUID

chmod g+s filename — установка бита SGID

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

Родителем всех процессов в системе является процесс init. Его PID всегда 1, PPID — 0. Всю таблицу процессов можно представить себе в виде дерева, в котором корнем будет процесс init. Этот процесс хоть и не является частью ядра, но выполняет в системе очень важную роль — определяет текущий уровень инициализации системы и следит чтобы были запущены программы, позволяющие пользователю общаться с компьютером (mingetty, X или другие).

Процессы, имена которых заключены в квадратные скобки, например «[keventd]» — это процессы ядра. Эти процессы управляют работой системы, а точнее такими ее частями, как менеджер памяти, планировщик времени процессора, менеджеры внешних устройств и так далее.

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

Жизнь каждого процесса представлена следующими фазами:

Создание процесса — на этом этапе создается полная копия того процесса, который создает новый. Например, вы запустили из интерпретатора на выполнение команду ls. Командный интерпретатор создает свою полную копию.

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

Выполнение процесса

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

Умирание процесса — после всех завершающих стадий удаляется запись из таблицы процессов — процесс завершил свою работу.

Во время работы процесса, ядро контролирует его состояние, и в случае возникновения непредвиденной ситуации управляет процессом с помощью посылки ему сигнала. Сигнал — это простейший способ межпроцессорного (то есть между процессами) взаимодействия. Существует несколько типов сигналов. Для каждого из типов предусмотрено действие по умолчанию. Процесс может воспользоваться действием по умолчанию, или, если у него есть обработчик сигнала, то он может перехватить и обработать или игнорировать сигнал. Сигналы SIGKILL и SIGSTOP невозможно ни перехватить, ни игнорировать.

По умолчанию возможны несколько действий:

игнорировать — продолжать работу, несмотря на то, что получен сигнал.

завершить — завершить работу процесса.

завершить + core — завершить работу процесса и создать файл в текущем каталоге с именем core, содержащий образ памяти процесса (код и данные).

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

Вот список всех сигналов, существующих в системе на сегодняшний день:

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

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

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

Что такое процесс?

Процесс Linux — это экземпляр программы, запущенный в памяти. Все процессы можно разделить на обычные и фоновые. Более подробно об этом написано в статье управление процессами Linux. Linux — это многопользовательская система, каждый пользователь может запускать одни и те же программы, и даже один пользователь может захотеть запустить несколько экземпляров одной программы, поэтому ядру нужно как-то идентифицировать такие однотипные процессы. Для этого каждому процессу присваивается PID (Proccess Identificator).

Каждый из процессов может находиться в одном из таких состояний:

  • Запуск — процесс либо уже работает, либо готов к работе и ждет, когда ему будет дано процессорное время;
  • Ожидание — процессы в этом состоянии ожидают какого-либо события или освобождения системного ресурса. Ядро делит такие процессы на два типа — те, которые ожидают освобождения аппаратных средств и приостановление с помощью сигнала;
  • Остановлено — обычно, в этом состоянии находятся процессы, которые были остановлены с помощью сигнала;
  • Зомби — это мертвые процессы, они были остановлены и больше не выполняются, но для них есть запись в таблице процессов, возможно, из-за того, что у процесса остались дочерние процессы.

А теперь давайте перейдем ближе к практике и поговорим о том, как узнать запущенные процессы linux.

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

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

$ ps опции

$ ps опции | grep параметр

Во втором варианте мы используем утилиту grep для того, чтобы отобрать нужные нам процессы по определенному критерию. Теперь рассмотрим опции утилиты. Они делятся на два типа — те, которые идут с дефисом Unix и те, которые используются без дефиса — BSD. Лучше пользоваться только опциями Unix, но мы рассмотрим и одни и другие. Заметьте, что при использовании опций BSD, вывод утилиты будет организован в BSD стиле.

  • -A, (a) — выбрать все процессы;
  • -a — выбрать все процессы, кроме фоновых;
  • -d, (g) — выбрать все процессы, даже фоновые, кроме процессов сессий;
  • -N — выбрать все процессы кроме указанных;
  • — выбирать процессы по имени команды;
  • -G — выбрать процессы по ID группы;
  • -p, (p) — выбрать процессы PID;
  • —ppid — выбрать процессы по PID родительского процесса;
  • -s — выбрать процессы по ID сессии;
  • -t, (t) — выбрать процессы по tty;
  • -u, (U) — выбрать процессы пользователя.
  • — отображать информацию планировщика;
  • -f — вывести максимум доступных данных, например, количество потоков;
  • -j, (j) — вывести процессы в стиле Jobs, минимум информации;
  • -M, (Z) — добавить информацию о безопасности;
  • -o, (o) — позволяет определить свой формат вывода;
  • —sort, (k) — выполнять сортировку по указанной колонке;
  • -L, (H)— отображать потоки процессов в колонках LWP и NLWP;
  • -m, (m) — вывести потоки после процесса;
  • -V, (V) — вывести информацию о версии;
  • -H — отображать дерево процессов linux;

Теперь, когда вы знаете синтаксис и опции, можно перейти ближе к практике и посмотреть запущенные процессы в Linux. Чтобы просто посмотреть процессы в linux в текущей оболочке используйте команду без параметров:

Все процессы, кроме лидеров групп, в том же режиме отображения:

Все процессы, включая фоновые и лидеры групп:

Чтобы вывести больше информации о процессах используйте опцию -f:

При использовании опции -f команда выдает такие колонки:

  • UID — пользователь, от имени которого запущен процесс;
  • PID — идентификатор процесса;
  • PPID — идентификатор родительского процесса;
  • C — процент времени CPU, используемого процессом;
  • STIME — время запуска процесса;
  • TTY — терминал, из которого запущен процесс;
  • TIME — общее время процессора, затраченное на выполнение процессора;
  • CMD— команда запуска процессора;
  • LWP — показывает потоки процессора;
  • PRI — приоритет процесса.

Например, также можно вывести подробную информацию обо всех процессах:

Больше информации можно получить, использовав опцию -F:

Если вы хотите получить еще больше информации, используйте вместо -f опцию -l:

Дальше мы можем отобрать все процессы, запущенные от имени определенного пользователя:

С помощью опции -H можно отобразить дерево процессов:

Если вас интересует информация только об определенном процессе, то вы можете использовать опцию -p и указать pid процесса linux:

Через запятую можно указать несколько PID:

Опция позволяет фильтровать процессы по имени, например, выберем только процессы chrome:

Дальше можно использовать опцию -L чтобы отобразить информацию о процессах:

Очень интересно то, с помощью опции -o можно настроить форматирование вывода, например, вы можете вывести только pid процесса linux и команду:

Вы можете выбрать такие колонки для отображения: pcpu, pmem, args, comm, cputime, pid, gid, lwp, rss, start, user,vsize,priority. Для удобства просмотра можно отсортировать вывод программы по нужной колонке, например, просмотр процессов linux, которые используют больше всего памяти:

Читать еще:  Идентификатор процесса linux

Или по проценту загрузки cpu:

ps -FA —sort pcpu

Еще одна опция — M, которая позволяет вывести информацию про права безопасности и флаги SELinux для процессов:

Общее количество запущенных процессов Linux можно узнать командой:

Мы рассмотрели все основные возможности утилиты ps. Дальше вы можете поэкспериментировать с ее параметрами и опциями чтобы найти нужные комбинации, также можно попытаться применить опции BSD.

Выводы

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

Процессы Linux

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

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

Модель памяти процесса

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

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

Создание процесса и выполнение программы

Процесс может создать новый процесс с помощью системного вызова fork() . Процесс, вы­зывающий fork() , известен кък родительский процесс, а новый процесс называется дочерним процессом. Ядро создает дочерний процесс путем изготовления дубликата родительского

процесса. Дочерний процесс наследует копии родительских сегментов данных, стека и кучи, которые затем могут изменяться независимо от своих родительских копий. (Текст програм­мы размещается в области памяти с пометкой «только для чтения» и совместно используется двумя процессами.)

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

У вызова execve()) есть ряд надстроек в виде родственных функций библиотеки язы­ка С с несколько отличающимся интерфейсом, но сходной функциональностью. У всех этих функций имена начинаются со строки ехес . (В тех случаях, когда разница между ними неважна, мы будем для общей ссылки на эти функции использовать обозначение ехес() . И все же следует иметь в виду, что на самом деле функции по имени ехес() не существует.)

В основном глагол «выполнять» ( ехес ) будет употребляться для описания операций, выполняемых execve()) и ее библиотечными функциями-надстройками.

Идентификатор процесса и идентификатор родительского процесса

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

Завершение процесса и код завершения

Процесс может быть завершен двумя способами: запросом своего собственного заверше­ния с использованием системного вызова _exit() (или родственной ему библиотечной функции exit() ) или путем его уничтожения извне с помощью сигнала. В любом слу­чае процесс выдает код завершения, небольшое неотрицательное целое число, которое может быть проверено родительским процессом с использованием системного вызова wait() . В случае вызова _exit() процесс явным образом указывает свой собственный код завершения. Если процесс уничтожается сигналом, код завершения устанавлива­ется по типу сигнала, уничтожившего процесс. (Иногда мы будем называть аргумент, передаваемый _exit() , кодом выхода процесса, чтобы отличить его от кода завершения, который является либо значением, переданным _exit() , либо указателем на сигнал, уничтоживший процесс.)

По соглашению, код завершения 0 служит признаком успешного завершения процесса, а ненулевое значение служит признаком возникновения какой-то ошибки. Большинство оболочек позволяют получить код завершения последней выполненной программы с по­мощью переменной оболочки по имени $? .

Принадлежащие процессу идентификаторы пользователя и группы (учетные данные)

У каждого процесса имеется несколько связанных с ним идентификаторов пользователей ( UID ) и групп ( GID ). К ним относятся следующие.

  • Реальный идентификатор пользователя и реальный идентификатор группы. Они идентифицируют пользователя и группу, которым принадлежит процесс. Новый про­цесс наследует эти идентификаторы ( ID ) от своего родительского процесса. Оболочка входа в систему получает свой реальный UID и реальный GID от соответствующих полей в системном файле паролей.
  • Действующий идентификатор пользователя и действующий идентификатор группы.
  • Эти два идентификатора (в сочетании с рассматриваемыми сразу после них дополнительными идентификаторами групп) используются при определении прав досту­па, имеющихся у процесса при доступе к защищенным ресурсам, таким как файлы и объекты обмена данными между процессами. Обычно имеющиеся у процессов действующие идентификаторы содержат те же значения, что и соответствующие им реальные ID . При изменении действующих идентификаторов процессу можно присваивать права доступа другого пользователя или группы, в порядке, который вскоре будет рассмотрен.
  • Дополнительные идентификаторы группы. Они позволяют определить дополнительные группы, которым принадлежит процесс. Новый процесс наследует свои дополнительные идентификаторы групп от своего родительского процесса. Оболочка входа в систему получает свои дополнительные идентификаторы групп от системного файла групп.

Привилегированные процессы

Традиционно в системах UNIX привилегированным считается процесс, чей действующий идентификатор пользователя имеет значение 0 (привилегированный пользователь, супер­пользователь). Такой процесс обходит ограничения прав доступа, обычно применяемые ядром. И наоборот, непривилегированным называется процесс, запущенный другими поль­зователями. Такие процессы имеют ненулевой действующий UID и должны соблюдать навязываемые ядром правила разрешения доступа.

Процесс может быть привилегированным из-за того, что был создан другим привилегированным процессом, например оболочкой входа в систему, запущенной суперполь­зователем (root). Еще один способ получения процессом привилегированности связан с механизмом установки идентификатора пользователя ( set-user-ID ), который позволяет присвоить процессу такой же действующий идентификатор пользователя, как и иденти­фикатор пользователя файла выполняемой программы.

Мандаты (возможности)

Начиная с ядра версии 2.2, Linux делит привилегии, традиционно предоставляемые су­перпользователю, на множество отдельных частей, называемых возможностями. Каждая привилегированная операция связана с конкретной возможностью, и процесс может выполнить операцию, только если у него имеется соответствующая возможность. Традиционный привилегированный процесс (с действующим идентификатором пользователя, равным 0 ) соответствует процессу со всеми включенными возможностями.

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

Процесс init

При загрузке системы ядро создает особый процесс, который называется init , «родитель всех процессов». Он ведет свое происхождение от программного файла /sbin/init . Все процессы в системе создаются (используя fork() ) либо процессом init , либо одним из его потомков. Процесс init всегда имеет идентификатор процесса 1 и запускается с правами до­ступа суперпользователя. Процесс init не может быть уничтожен (даже привилегированным пользователем) и завершается только при завершении работы системы. Основной задачей init является создание и слежение за процессами, требуемыми работающей системе. (По­дробности можно найти на странице руководства init(8) .)

Процессы-демоны

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

  • Он долгоживущий. Процесс-демон зачастую запускается при загрузке системы и про­должает свое существование до тех пор, пока работа системы не будет завершена.
  • Он запускается в фоновом режиме, и у него нет управляющего терминала, с которого он мог бы считывать ввод или на который он мог бы записывать вывод.
  • К примерам процессов-демонов относятся syslogd , который записывает сообщения в системный журнал, и httpd , который обслуживает веб-страницы посредством протокола передачи гипертекста — Hypertext Transfer Protocol (HTTP).

Список переменных среды

У каждого процесса имеется список переменных среды, являющийся набором переменных среды, который содержится в памяти пользовательского пространства процесса. Каждый элемент этого списка состоит из имени и связанного с ним значения. При создании нового процесса с помощью fork() он наследует копию среды своего родителя. Таким образом, среда предоставляет родительскому процессу механизм для обмена информацией с до­черним процессом. Когда процесс заменяет программу, запуская новую программу с по­мощью ехес() , последняя либо наследует среду, используемую старой программой, либо получает новую среду, указанную как часть вызова ехес() .

Переменные среды, как в следующем примере, создаются в большинстве оболочек командой export (или командой setenv в оболочке С shell):

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

Программы на языке С могут получать доступ к среде, используя внешнюю пере­менную ( char **environ ) и различные библиотечные функции, позволяющие процессу извлекать и изменять значения в его среде.

Переменные среды предназначены для различных целей. Например, оболочка опре­деляет и использует ряд переменных, к которым можно получить доступ из сценариев и программ, выполняемых из оболочки. В число таких переменных входят НОМЕ , указы­вающая путевое имя пользовательского каталога входа в систему, и PATH , указывающая список каталогов, в которых оболочка будет вести поиск программ, соответствующих введенным пользователем командам.

Ограничения ресурсов

Каждый процесс потребляет ресурсы, например открытые файлы, память и время цен­трального процессора. Используя системный вызов setrlimit() , процесс может устано­вить верхний предел своего потребления различных ресурсов. Каждый такой предел имеет два связанных с ним значения: мягкое ограничение, ограничивающее тот объем ресурса, который процесс может задействовать, и жесткое ограничение, представляющее собой верхний предел значения, которое может быть отрегулировано мягким ограничением. Непривилегированный процесс может изменить свое мягкое ограничение для конкрет­ного ресурса на любое значение в диапазоне от нуля и до соответствующего жесткого ограничения, но свое жесткое ограничение он может только понизить.

Читать еще:  Утилиты для ускорения игр

Когда с помощью fork() создается новый процесс, он наследует копии настроек огра­ничений ресурсов от своего родительского процесса.

Ограничения ресурсов оболочки могут быть отрегулированы с использованием коман­ды ulimit ( limit в оболочке С shell). Эти настройки ограничений наследуются дочерними процессами, создаваемыми оболочкой для выполнения команд.

Процессы в Linux

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

Термин «процесс» впервые появился при разработке операционной системы Multix и имеет несколько определений, которые используются в зависимости от контекста. Процесс — это:

  1. программа на стадии выполнения
  2. «объект», которому выделено процессорное время
  3. асинхронная работа

Для описания состояний процессов используется несколько моделей. Самая простая модель — это модель трех состояний. Модель состоит из:

  1. состояния выполнения
  2. состояния ожидания
  3. состояния готовности

Выполнение — это активное состояние, во время которого процесс обладает всеми необходимыми ему ресурсами. В этом состоянии процесс непосредственно выполняется процессором.

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

Готовность — это тоже пассивное состояние, процесс тоже заблокирован, но в отличие от состояния ожидания, он заблокирован не по внутренним причинам (ведь ожидание ввода данных — это внутренняя, «личная» проблема процесса — он может ведь и не ожидать ввода данных и свободно выполняться — никто ему не мешает), а по внешним, независящим от процесса, причинам. Когда процесс может перейти в состояние готовности? Предположим, что наш процесс выполнялся до ввода данных. До этого момента он был в состоянии выполнения, потом перешел в состояние ожидания — ему нужно подождать, пока мы введем нужную для работы процесса информацию. Затем процесс хотел уже перейти в состояние выполнения, так как все необходимые ему данные уже введены, но не тут-то было: так как он не единственный процесс в системе, пока он был в состоянии ожидания, его «место под солнцем» занято — процессор выполняет другой процесс. Тогда нашему процессу ничего не остается как перейти в состояние готовности: ждать ему нечего, а выполняться он тоже не может.

Из состояния готовности процесс может перейти только в состояние выполнения. В состоянии выполнения может находится только один процесс на один процессор. Если у вас n-процессорная машина, у вас одновременно в состоянии выполнения могут быть n процессов.

Из состояния выполнения процесс может перейти либо в состояние ожидания или состояние готовности. Почему процесс может оказаться в состоянии ожидания, мы уже знаем — ему просто нужны дополнительные данные или он ожидает освобождения какого-нибудь ресурса, например, устройства или файла. В состояние готовности процесс может перейти, если во время его выполнения, квант времени выполнения «вышел». Другими словами, в операционной системе есть специальная программа — планировщик, которая следит за тем, чтобы все процессы выполнялись отведенное им время. Например, у нас есть три процесса. Один из них находится в состоянии выполнения. Два других — в состоянии готовности. Планировщик следит за временем выполнения первого процесса, если «время вышло», планировщик переводит процесс 1 в состояние готовности, а процесс 2 — в состояние выполнения. Затем, когда, время отведенное, на выполнение процесса 2, закончится, процесс 2 перейдет в состояние готовности, а процесс 3 — в состояние выполнения.

Диаграмма модели трех состояний представлена на рисунке 1.

Рисунок 1. Модель трех состояний

Более сложная модель — это модель, состоящая из пяти состояний. В этой модели появилось два дополнительных состояния: рождение процесса и смерть процесса. Рождение процесса — это пассивное состояние, когда самого процесса еще нет, но уже готова структура для появления процесса. Как говорится в афоризме: «Мало найти хорошее место, надо его еще застолбить», так вот во время рождения как раз и происходит «застолбление» этого места. Смерть процесса — самого процесса уже нет, но может случиться, что его «место», то есть структура, осталась в списке процессов. Такие процессы называются зобми и о них мы еще поговорим в этой статье.

Диаграмма модели пяти состояний представлена на рисунке 2.

Рисунок 2. Модель пяти состояний

Над процессами можно производить следующие операции:

  1. Создание процесса — это переход из состояния рождения в состояние готовности
  2. Уничтожение процесса — это переход из состояния выполнения в состояние смерти
  3. Восстановление процесса — переход из состояния готовности в состояние выполнения
  4. Изменение приоритета процесса — переход из выполнения в готовность
  5. Блокирование процесса — переход в состояние ожидания из состояния выполнения
  6. Пробуждение процесса — переход из состояния ожидания в состояние готовности
  7. Запуск процесса (или его выбор) — переход из состояния готовности в состояние выполнения

Для создания процесса операционной системе нужно:

  1. Присвоить процессу имя
  2. Добавить информацию о процессе в список процессов
  3. Определить приоритет процесса
  4. Сформировать блок управления процессом
  5. Предоставить процессу нужные ему ресурсы

Подробнее о списке процессов, приоритете и обо всем остальном мы еще поговорим, а сейчас нужно сказать пару слов об иерархии процессов. Процесс не может взяться из ниоткуда: его обязательно должен запустить какой-то процесс. Процесс, запущенный другим процессом, называется дочерним (child) процессом или потомком. Процесс, который запустил процесс называется родительским (parent), родителем или просто — предком. У каждого процесса есть два атрибута — PID (Process ID) — идентификатор процесса и PPID (Parent Process ID) — идентификатор родительского процесса.

Процессы создают иерархию в виде дерева. Самым «главным» предком, то есть процессом, стоящим на вершине этого дерева, является процесс init (PID=1).

На мой взгляд, приведенной теории вполне достаточно, чтобы перейти к практике, а именно — «пощупать» все состояния процессов. Конечно, мы не рассмотрели системные вызовы fork(), exec(), exit(), kill() и многие другие, но в Сети предостаточно информации об этом. Тем более, что про эти вызовы вы можете прочитать в справочной системе Linux, введя команду man fork. Правда, там написано на всеми любимом English, так что за переводом (если он вам нужен) все-таки придется обратиться за помощью к WWW.

Для наблюдения за процессами мы будем использовать программу top.

Полный вывод программы я по понятным причинам урезал. Рассмотрим по порядку весь вывод программы. В первой строке программа сообщает текущее время, время работы системы ( 58 min), количество зарегистрированных (login) пользователей (4 users), общая средняя загрузка системы (load average).

Примечание. Общей средней загрузкой системы называется среднее число процессов, находящихся в состоянии выполнения (R) или в состоянии ожидания (D). Общая средняя загрузка измеряется каждые 1, 5 и 15 минут.

Во второй строке вывода программы top сообщается, что в списке процессов находятся 52 процесса, из них 51 спит (состояние готовности или ожидания), 1 выполняется (у меня только 1 процессор), 0 процессов зомби и 0 остановленных процессов.

В третьей-пятой строках приводится информация о загрузке процессора, использования памяти и файла подкачки. Нас данная информация не очень интересует, поэтому переходим сразу к таблице процессов.

В таблице отображается различная информация о процессе. Нас сейчас интересуют колонки PID (идентификатор процесса), USER (пользователь, запустивший процесс), STAT (состояние процесса) и COMMAND (команда, которая была введена для запуска процесса).

Колонка STAT может содержать следующие значения:

    R — процесс выполняется или готов к выполнению (состояние готовности)
  • D — процесс в «беспробудном сне» — ожидает дискового ввода/вывода
  • T — процесс остановлен (stopped) или трассируется отладчиком
  • S — процесс в состоянии ожидания (sleeping)
  • Z — процесс-зобми
  • &lt — процесс с отрицательным значением nice
  • N — процесс с положительным значением nice (о команде nice мы поговорим позже)

Давайте просмотрим, когда же процесс находится в каждом состоянии. Создайте файл process — это обыкновенный bash-сценарий

Сделайте этот файл исполнимым chmod +x ./process и запустите его ./process. Теперь перейдите на другую консоль (ALT + Fn) и введите команду ps -a | grep process. Вы увидите следующий вывод команды ps:

Данный вывод означает, что нашему процессу присвоен идентификатор процесса 4035. Теперь введите команду top -p 4035

Обратите внимание на колонку состояния нашего процесса. Она содержит значение R, которое означает, что в данный момент выполняется процесс с номером 4035.

Теперь приостановим наш процесс — состояние T. Перейдите на консоль, на которой запущен ./process и нажмите Ctrl + Z. Вы увидите сообщение Stopped.

Теперь попробуем «усыпить» наш процесс. Для этого нужно сначала «убить» его: kill 4035. Затем добавить перед циклом while в сценарии ./process строку sleep 10m, которая означает, что процесс будет спать 10 минут. После этого опять запустите команду ps -a | grep process, чтобы узнать PID процесса, а затем — команду top -p PID. Вы увидите в колонке состояния букву S, что означает, что процесс находится в состоянии ожидания или готовности — попросту говоря «спит».

Мы вплотную подошли к самому интересному — созданию процесса-зомби. Во многих статьях, посвященных процессам, пишется «зомби = не жив, не мертв». А что это означает на самом деле? При завершении процесса должна удаляться его структура из списка процессов. Иногда процесс уже завершился, но его имя еще не удалено из списка процессов. В этом случае процесс становится зомби — его уже нет, но мы его видим в таблице команды top. Такое может произойти, если процесс-потомок (дочерний процесс) завершился раньше, чем этого ожидал процесс-родитель. Сейчас мы напишем программу, порождающую зомби, который будет существовать 8 секунд. Процесс-родитель будет ожидать завершения процесса-потомка через 10 секунд, а процесс-потомок завершить через 2 секунды.

Для компиляции данной программы нам нужен компилятор gcc:

Для тех, у кого не установлен компилятор, скомпилированная программа доступна отсюда.

После того, как программа будет откомпилирована, запустите ее: ./zombie. Программа выведет следующую информацию:

Запомните последний номер и быстро переключайтесь на другую консоль. Затем введите команду top -p 1148

Мы видим, что в списке процессов появился 1 зомби (STAT=Z), который проживет аж 10 секунд.

Мы уже рассмотрели все возможные состояния процессов. Осталось только рассмотреть команду для повышения приоритета процесса — это команда nice. Повысить приоритет команды может только пользователь root, указав соответствующий коэффициент понижения. Для увеличения приоритета нужно указать отрицательный коэффициент, например, nice -5 process

Ссылка на основную публикацию
ВсеИнструменты 220 Вольт
Adblock
detector
×
×