Linux запустить процессы параллельно

Распараллеливание задач в Linux

Потребовалось мне перекодировать некоторое количество видео-файлов. Для этого я написал следующий сценарий:

recode() <
mencoder -o $2 $1 -ovc x264 -x264encopts bitrate=22000:keyint=50 -oac mp3lame -lameopts vbr=3:br=320 -fps 50
>
recode input/00108.mts 00108.avi
recode input/00109.mts 00109.avi
.
.

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

Первый способ: распараллеливание средствами mencoder

Можно задать опции mencoder. Для x264 кодека есть возможность указать количество потоков:

  • threads=
    Использовать потоки для кодирования одновременно на нескольких процессорах (по умолчанию: 1). Это немного ухудшает качество кодирования. 0 или ‘auto’ — автоматически определить количество процессоров и использовать соответствующее количество потоков.

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

Второй способ: распараллеливание средствами Bash

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

(recode input/00108.mts 00108.avi
recode input/00109.mts 00109.avi
.
. ) &
(recode input/00108.mts 00110.avi
recode input/00109.mts 00111.avi
.
. )

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

Третий способ: распараллеливание средствами GNU make

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

all: 00108.avi 00109.avi 00110.avi 00111.avi 00118.avi 00119.avi 00120.avi 00123.avi

Получилось на удивление просто и коротко. В начале перечисляется список всех файлов, которые я хочу получить. За ним следует путь до исходных файлов и правило сборки. Запускать командой «make -j 2», чтобы работало одновременно 2 процесса.

Источник

PDSH: Параллельное выполнение команд на нескольких Linux-серверах

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

PDSH (parallel distributed shell) — высокопроизводительная утилита для параллельного запуска команд на большом количестве Linux-серверов через ssh. По умолчанию pdsh позволяет поддерживать 32 параллельных соединения с управляемыми северами. Для pdsh есть несколько полезных модулей расширения, которые мы также рассмотрим в этой статье.

С помощью pdsh вы можете:

  • Обновлять ПО на серверах;
  • Установить необходимые модули или утилиты;
  • Запустить какой-то bash скрипт;
  • Проверить наличие обновлений и многое другое.

Установка PDSH и дополнительных модулей

Сначала нужно установить утилиту pdsh и нужные модули. В CentOS установка выполняется через менеджер пакетов yum:

yum install epel-release -y – подключаем репозиторий Epel

yum install pdsh pdsh-mod-genders -y — устанавливаем pdsh и модуль genders для него.

В целом для настройки pdsh больше ничего и не нужно. Мы установили сам pdsh, а так же установили дополнительный модуль pdsh-mod-genders, о котором я расскажу чуть позже, когда мы перейдем к запуску команд на удаленных серверах.

Настройка сервера управления pdsh и управляемых Linux-серверов.

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

Запустив команду ssh-keygen -q на все вопросы просто жмем Enter. Ключ готов, теперь осталось скопировать его на управляемые Linux-сервера. В качестве примера я взял 2 сервера с Linux CentOS.

На управляемых серверах создайте директорию для ssh ключа (если таковой нет):

Скопируем ключ в данный каталог, я это делаю через echo:

echo -e «ваш ключ с файла /root/.ssh/id_rsa.pub» >> /root/.ssh/authorized_keys

Ключ добавлен, нужно проверить проходит ли соединение с pdsh-сервера:

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

Так как ряд серверов может отличаться по hostname , я для себя сделал такую схему настройки PDSH. В файл hosts на управляющем сервере с pdsh я добавляю каждый управляемый сервер и присваиваю ему удобное мне имя, например:

Где вместо звездочек нужно указать IP destination-серверов.

Чтобы pdsh мог подключиться на заданные имена серверов, в файле /root/ssh/known_hosts к ключу каждого управляемого сервера, через запятую нужно добавить желаемое имя сервера, которое мы указали в /etc/hosts. Например:

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

Для запуска команды на удаленном сервере через pdsh используется такой конструкция:

pdsh -w server1 ‘команда’ — я всегда советую брать в кавычки запускаемые команды, так как если вы будете использовать спецсимволы, bash на сервере с pdsh выполнит команду после спецсимвола локально.

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

pdsh -w server1 ‘date’

pdsh -w server2 ‘date’

Или выполнить одну команду сразу для списка серверов:

pdsh -w server1,server2 ‘date’

Если нужно выполнить команду на 10-ти серверах, получится довольно длинная команда с перечислением всех серверов, что неудобно. Т.к. мы задали собственные hostname для серверов, и pdsh это понимает, при вызове pdsh можно укажите конкретные сервера или диапазон серверов в квадратных скобках:

pdsh -w server2 ‘date’ — диапазон серверов в моем случае 2 сервера. Может быть от 1 до 20, выглядеть будет так: pdsh -w server3 ‘date’

pdsh -w server[1,2] ‘date’ — конкретные сервера 1 и 2, можно выбрать например 3-4 сервера и команды будет выглядеть следующим образом: pdsh -w server[1,2,7,9] ‘date’

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

pdsh -w server15 ‘uptime’ | sort -n

Рассмотрим ранее установленный модуль pdsh-mod-gendors. Чтобы воспользоваться им, создадим сам файл:

Для чего же он нужен? Genders – это файл с собственным синтаксисом для описания ролей pdsh. Как его можно применить в работе? Например:

    У вас есть 10 серверов с Ubuntu. Мы объединим их в одну группу Ubuntu, пусть их хостнеймы будут ubuntu1-10.
    В файл /etc/genders прописываем следующие строки:

  • У вас есть 10 серверов с Centos и аналогичные хостнеймы — centos1-10:
  • Так же есть группа серверов для разработчиков — web1-10:
  • Если есть группа серверов с разными именами, например sys2 и adm7:
  • Т.е. в файле /etc/genders вы можете создать различные группы Linux серверов. Чтобы pdsh читал данные из файла genders при запуске вместо ключа –w нужно указывать –g.

    Читайте также:  Amigo браузер для windows

    В моем случае сервера по-прежнему два, но это ничего не меняет:

    [root@server etc]# pdsh -g centos ‘date’

    Так гораздо удобнее и команда выполняется на всех серверах в группе.
    По умолчанию pdsh позволяет запускать до 32 параллельных сессий на разных серверах. Количество одновременно запущенных команд указывается с помощью ключа –f. Например, при -f 1 пока команда не выполнится на первом сервере, ко второму она не перейдет.

    На примере нашей команды это выглядит так:

    pdsh -g ubuntu ‘date’ -f 1

    Так же можно применять ключи -t и -u:

    • -t – установить время ожидания подключения в секундах;
    • -u – установить время ожидания выполнения удаленной команды.

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

    Следующая команда на всех указанных серверха выполнит переход в указанноу нам директорию и скачает в нее iso-образ Centos 7:

    pdsh -w server[1,2] ‘cd /root && wget _http://mirror.yandex.ru/centos/7.7.1908/isos/x86_64/CentOS-7-x86_64-Minimal-1908.iso’

    Хотите быстро проверить какие репозитории установлены на управляемых серверах?

    pdsh -w server[1,2] ‘yum repolist’

    pdsh -w server[1,2] ‘yum install httpd -y’ – установка apache на оба сервера

    И проверим установилось ли действительно:

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

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

    Источник

    Многозадачность в shell-скриптах

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

    Все примеры написаны на bash, но (с минимальными изменениями) будут работать в ksh. В csh тоже есть средстава управления фоновыми процессами, поэтому подобных подход тоже может быть использован.

    JOB CONTROL

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

    command & — запускает команду в фоне
    jobs — печатает список фоновых команд

    Простой пример, не выполняющий никаких полезных действий. Из файла test.txt читаются числа, и параллельно запускается 3 процесса, которые спят соответствующее количество секунд. Каждые три секунды проверяется число запущенных процессов, и если их меньше трех, запускается новый. Запуск фонового процесса вынесен в отдельную функцию mytask, но можно запускть его непосредственно в цикле.

    Обратите внимание на wait после цикла, команда ждет завершения исполняющихся в фоне процессов. Без нее скрипт будет завершен сразу после завершения цикла и все фоновые процессы будут прерваны. Возможно именно этот wait упоминается в известном меме «oh, wait. ».

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

    Если прервать скрипт по Ctrl-C, он будет убит со всеми фоновыми процессами, т.к. все процессы работающие в терминале получают сигналы от клавиатуры (например, SIGINT). Если же скрипт убить из другого терминала командой kill, то фоновые процессы останутся работать до завершения и об этом нужно помнить.

    /tmp2 $ ps -ef | grep -E «test|sleep»
    user 1363 775 0 12:31 pts/5 00:00:00 ./test.sh
    user 1368 1363 0 12:31 pts/5 00:00:00 ./test.sh
    user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils —coreutils-prog-shebang=sleep /usr/bin/sleep 60
    user 1373 1363 0 12:31 pts/5 00:00:00 ./test.sh
    user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils —coreutils-prog-shebang=sleep /usr/bin/sleep 50
    user 1378 1363 0 12:31 pts/5 00:00:00 ./test.sh
    user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils —coreutils-prog-shebang=sleep /usr/bin/sleep 30
    user 1387 1363 0 12:31 pts/5 00:00:00 /usr/bin/coreutils —coreutils-prog-shebang=sleep /usr/bin/sleep 3
    user 1389 556 0 12:31 pts/2 00:00:00 grep —colour=auto -E test|sleep
    user@somehost

    /tmp2 $ kill 1363
    user@somehost

    /tmp2 $ ps -ef | grep -E «test|sleep»
    user 1368 1 0 12:31 pts/5 00:00:00 ./test.sh
    user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils —coreutils-prog-shebang=sleep /usr/bin/sleep 60
    user 1373 1 0 12:31 pts/5 00:00:00 ./test.sh
    user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils —coreutils-prog-shebang=sleep /usr/bin/sleep 50
    user 1378 1 0 12:31 pts/5 00:00:00 ./test.sh
    user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils —coreutils-prog-shebang=sleep /usr/bin/sleep 30
    user 1399 556 0 12:32 pts/2 00:00:00 grep —colour=auto -E test|sleep

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

    Источник

    Процессы

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

    Выполняющаяся программа называется в Linux процессом. Все процессы система регистрирует в таблице процессов, присваивая каждому уникальный номер — идентификатор процесса (process identificator, PID). Манипулируя процессами, система имеет дело именно с их идентификаторами, другого способа отличить один процесс от другого, по большому счёту, нет. Для просмотра своих процессов можно воспользоваться утилитой ps («process status»):

    [methody@localhost methody]$ ps -f
    UID PID PPID C STIME TTY TIME CMD
    methody 3590 1850 0 13:58 tty3 00:00:00 -bash
    methody 3624 3590 0 14:01 tty3 00:00:00 ps -f

    Пример 1. Просмотр таблицы собственных процессов

    Здесь Мефодий вызвал ps с ключом « -f » («full»), чтобы добыть побольше информации. Представлены оба принадлежащих ему процесса: стартовый командный интерпретатор, bash , и выполняющийся ps . Оба процесса запущены с терминала tty3 (третьей системной консоли), и имеют идентификаторы 3590 и 3624 соответственно. В поле PPID («parent process identificator») указан идентификатор родительского процесса, т. е. процесса, породившего данный. Для ps это — bash , а для bash , очевидно, login , так как именно он запускает стартовый shell. В выдаче не оказалось строки для этого login , равно как и для большинства других процессов системы, так как они не принадлежат пользователю methody .

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

    Запуск дочерних процессов

    Запуск одного процесса вместо другого устроен в Linux с помощью системного вызова exec() . Старый процесс из памяти удаляется навсегда, вместо него загружается новый, при этом настройка окружения не меняется, даже PID остаётся прежним. Вернуться к выполнению старого процесса невозможно, разве что запустить его по новой с помощью того же exec() (от «execute» — «исполнить»). Кстати, имя файла (программы), из которого запускается процесс, и собственное имя процесса (в таблице процессов) могут и не совпадать. Собственное имя процесса — это такой же параметр командной строки, как и те, что передаются ему пользователем: для exec() требуется и путь к файлу, и полная командная строка, нулевой (стартовый) элемент которой — как раз название команды

    Читайте также:  Minecraft windows 10 edition repack

    Нулевой параметр — argv[0] в терминах языка Си и $0 в терминах shell

    Вот откуда « — » в начале имени стартового командного интерпретатора ( -bash ): его «подсунула» программа login , чтобы была возможность отличать его от других запущенных тем же пользователем оболочек.

    Для работы командного интерпретатора недостаточно одного exec() . В самом деле, shell не просто запускает утилиту, а дожидается её завершения, обрабатывает результаты её работы и продолжает диалог с пользователем. Для этого в Linux служит системный вызов fork() («вилка, развилка»), применение которого приводит к возникновению ещё одного, дочернего, процесса — точной копии породившего его родительского. Дочерний процесс ничем не отличается от родительского: имеет такое же окружение, те же стандартный ввод и стандартный вывод, одинаковое содержимое памяти и продолжает работу с той же самой точки (возврат из fork() ). Отличия два: во-первых, эти процессы имеют разные PID, под которыми они зарегистрированы в таблице процессов, а во-вторых, различается возвращаемое значение fork() : родительский процесс получает в качестве результата fork() идентификатор процесса-потомка, а процесс-потомок получает « 0 ».

    Дальнейшие действия shell при запуске какой-либо программы очевидны. Shell-потомок немедленно вызывает эту программу с помощью exec() , а shell-родитель дожидается завершения работы процесса-потомка (PID которого ему известен) с помощью ещё одного системного вызова, wait() . Дождавшись и проанализировав результат команды, shell продолжает работу.

    [methody@localhost methody]$ cat > loop
    while true; do true; done
    ^D
    [methody@localhost methody]$ sh loop
    ^C
    [methody@localhost methody]$

    Пример 2. Создание бесконечно выполняющегося сценария

    По совету Гуревича Мефодий создал сценарий для sh (или bash , на таком уровне их команды совпадают), который ничего не делает. Точнее было бы сказать, что этот сценарий делает ничего, бесконечно повторяя в цикле команду, вся работа которой состоит в том, что она завершается без ошибок (в лекции Работа с текстовыми данными будет сказано о том, что « >файл » в командной строке просто перенаправляет стандартный вывод команды в файл ). Запустив этот сценарий с помощью команды вида sh имя_сценария , Мефодий ничего не увидел, но услышал, как загудел вентилятор охлаждения центрального процессора: машина трудилась! Управляющий символ « ^C », как обычно, привёл к завершению активного процесса, и командный интерпретатор продолжил работу.

    Если бы в описанной выше ситуации родительский процесс не ждал, пока дочерний завершится, а сразу продолжал работать, получилось бы, что оба процесса выполняются «параллельно»: пока запущенный процесс что-то делает, пользователь продолжает командовать оболочкой. Для того, чтобы запустить процесс параллельно, в shell достаточно добавить « & » в конец командной строки:

    [methody@localhost methody]$ sh loop&
    [1] 3634
    [methody@localhost methody]$ ps -f
    UID PID PPID C STIME TTY TIME CMD
    methody 3590 1850 0 13:58 tty3 00:00:00 -bash
    methody 3634 3590 99 14:03 tty3 00:00:02 sh loop
    methody 3635 3590 0 14:03 tty3 00:00:00 ps -f

    Пример 3. Запуск фонового процесса

    В результате стартовый командный интерпретатор (PID 3590 ) оказался отцом сразу двух процессов: sh , выполняющего сценарий loop и ps .

    Процесс, запускаемый параллельно, называется фоновым (background). Фоновые процессы не имеют возможности вводить данные с того же терминала, что и породивший их shell (только из файла), зато выводить на это терминал могут (правда, когда на одном и том же терминале вперемежку появляются сообщения от нескольких фоновых процессов, начинается сущая неразбериха). При каждом терминале в каждый момент времени может быть не больше одного активного (foreground) процесса, которому разрешено с этого терминала вводить. На время, пока команда (например, cat ) работает в активном режиме, породивший её командный интерпретатор «уходит в фон», и там, в фоне, выполняет свой wait() .

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

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

    В выдаче ps , которую получил Мефодий, можно заметить, что PID стартовой оболочки равен 3590 , а PID запущенных из-под него команд (одной фоновой и одной активной) — 3634 и 3635 . Это значит, что за время, прошедшее с момента входа Мефодия в систему до момента запуска sh loop& , в системе было запущено ещё 3634-3590=44 процесса. Что ж, в Linux могут одновременно работать несколько пользователей, да и самой системе иногда приходит в голову запустить какую-нибудь утилиту (например, выполняя действия по расписанию). А вот sh и ps получили соседние PID, значит, пока Мефодий нажимал Enter и набирал ps -f , никаких других процессов не запускалось.

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

    [methody@localhost methody]$ bash loop&
    [2] 3639
    [methody@localhost methody]$ top
    14:06:50 up 3:41, 5 users, load average: 1,31, 0,76, 0,42
    4 processes: 1 sleeping, 3 running, 0 zombie, 0 stopped
    CPU states: 99,4% user, 0,5% system, 0,0% nice, 0,0% iowait, 0,0% idle
    Mem: 514604k av, 310620k used, 203984k free, 0k shrd, 47996k buff
    117560k active, 148388k inactive
    Swap: 1048280k av, 0k used, 1048280k free 184340k cached

    PID USER PRI NI SIZE RSS SHARE STAT %CPU %MEM TIME COMMAND
    3639 methody 20 0 1260 1260 1044 R 50,3 0,2 0:12 bash
    3634 methody 18 0 980 980 844 R 49,1 0,1 3:06 sh
    3641 methody 9 0 1060 1060 872 R 0,1 0,2 0:00 top
    3590 methody 9 0 1652 1652 1264 S 0,0 0,3 0:00 bash

    Пример 4. Разделение времени между процессами

    Оказалось, что дерутся даже не два процесса, а три: sh (первый из запущенных интерпретаторов loop ), bash (второй) и сам top . Правда, по сведениям из поля %CPU , львиную долю процессорного времени отобрали sh и bash (они без устали вычисляют!), а top довольствуется десятой долей процента (а то и меньшей: ошибки округления). Стартовый bash вообще не хочет работать, он спит (значение « S », Sleep, поля STAT , status): ждёт завершения активного процесса, top .

    Читайте также:  Idmss lite аналог для windows

    Увидев такое разнообразие информации, Мефодий кинулся читать руководство по top, однако скоро понял, что без знания архитектуры Linux большая её часть не имеет смысла. Впрочем, некоторая часть всё же понятна: объём оперативной памяти (всей, используемой и свободной), время работы машины, объём памяти, занимаемой процессами и т. п.

    Последний процесс, запущенный из оболочки в фоне, можно из этой оболочки сделать активным при помощи команды fg («foreground» — «передний план»).

    [methody@localhost methody]$ fg
    bash loop
    ^C

    Пример 5. Перевод фонового процесса в активное состояние с помощью команды fg (foreground)

    Услужливый bash даже написал командную строку, какой был запущен этот процесс: « bash loop ». Мефодий решил «убить» его с помощью управляющего символа « ^C ». Теперь последним запущенным в фоне процессом стал sh , выполняющий сценарий loop .

    Сигналы

    Чтобы завершить работу фонового процесса с помощью « ^C », Мефодию пришлось сначала сделать его активным. Это не всегда возможно, и не всегда удобно. На самом деле, « ^C » — это не волшебная кнопка-убийца, а предварительно установленный символ (с ascii-кодом 3), при получении которого с терминала Linux передаст активному процессу сигнал 2 (по имени INT , от «interrupt» — «прервать»).

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

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

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

    [methody@localhost methody]$ sh loop
    ^Z
    [1]+ Stopped sh loop
    [methody@localhost methody]$ bg
    [1]+ sh loop &
    [methody@localhost methody]$ fg
    sh loop
    ^C
    [methody@localhost methody]$

    Пример 6. Перевод процесса в фон с помощью « ^Z » и bg

    Мефодий сначала запустил вечный цикл в качестве активного процесса, затем передал ему сигнал STOP с помощью « ^Z », после чего дал команду bg (back ground), запускающую в фоне последний остановленный процесс. Затем он снова перевёл этот процесс в активный режим, и, наконец, убил его.

    Передавать сигналы из командной строки можно любым процессам с помощью команды kill -сигнал PID или просто kill PID , которая передаёт сигнал 15 ( TERM ).

    [methody@localhost methody]$ sh
    sh-2.05b$ sh loop & bash loop &
    [1] 3652
    [2] 3653
    sh-2.05b$ ps -fH
    UID PID PPID C STIME TTY TIME CMD
    methody 3590 1850 0 13:58 tty3 00:00:00 -bash
    methody 3634 3590 87 14:03 tty3 00:14:18 sh loop
    methody 3651 3590 0 14:19 tty3 00:00:00 sh
    methody 3652 3651 34 14:19 tty3 00:00:01 sh loop
    methody 3653 3651 35 14:19 tty3 00:00:01 bash loop
    methody 3654 3651 0 14:19 tty3 00:00:00 ps -fH

    Пример 7. Запуск множества фоновых процессов

    Мефодий решил поназапускать процессов, а потом выборочно поубивать их. Для этого он, вдобавок к уже висящему в фоне sh loop , запустил в качестве активного процесса новый командный интерпретатор, sh (при этом изменилась приглашение командной строки). Из этого sh он запустил в фоне ещё один sh loop и новый bash loop . Сделал он это одной командной строкой (при этом команды разделяются символом « & », т. е. «И»; выходит так, что запускается и та, и другая команда). В ps он использовал новый ключ — « -H » («Hierarchy», «иерархия»), который добавляет в выдачу ps отступы, показывающие отношения «родитель–потомок» между процессами.

    sh-2.05b$ kill 3634
    [1]+ Terminated sh loop
    sh-2.05b$ ps -fH
    UID PID PPID C STIME TTY TIME CMD
    methody 3590 1850 0 13:58 tty3 00:00:00 -bash
    methody 3651 3590 0 14:19 tty3 00:00:00 sh
    methody 3652 3651 34 14:19 tty3 00:01:10 sh loop
    methody 3653 3651 34 14:19 tty3 00:01:10 bash loop
    methody 3658 3651 0 14:23 tty3 00:00:00 ps -fH

    Пример 8. Принудительное завершение процесса с помощью kill

    Мефодий принялся убивать! Для начала он остановил работу давно запущенного sh , выполнявшего сценарий с вечным циклом (PID 3634 ). Как видно из предыдущего примера, этот процесс за 16 минут работы системы съел не менее 14 минут процессорного времени, и конечно, ничего полезного не сделал. Сигнал о том, что процесс-потомок умер, дошёл до обработчика в стартовом bash (PID 3590 , и на терминал вывелось сообщение « [1]+ Terminated sh loop », после чего стартовый bash продолжил ждать завершения активного процесса — sh (PID 3651 ).

    sh-2.05b$ exit
    [methody@localhost methody]$ ps -fH
    UID PID PPID C STIME TTY TIME CMD
    methody 3590 1850 0 15:17 tty3 00:00:00 -bash
    methody 3663 3590 0 15:23 tty3 00:00:00 ps -fH
    methody 3652 1 42 15:22 tty3 00:00:38 bash loop
    methody 3653 1 42 15:22 tty3 00:00:40 sh loop
    [methody@localhost methody]$ kill -HUP 3652 3653
    [methody@localhost methody]$ ps
    PID TTY TIME CMD
    3590 tty3 00:00:00 bash
    3664 tty3 00:00:00 ps

    Пример 9. Завершение процесса естественным путём с помощью сигнала «Hang Up»

    Ждать ему оставалось недолго. Этот sh завершился естественным путём, от команды exit , оставив после себя двух детей-сирот (PID 3652 и 3653 ), которые тотчас же усыновил «отец всех процессов» — init (PID 1 ). Когда кровожадный Мефодий расправился и с ними — с помощью сигнала 1 ( HUP , то есть «Hang UP», «повесить») — некому было даже сообщить об их кончине (если бы процесс-радитель был жив, на связанный с ним терминал вывелось бы что-нибудь вроде « [1]+ Hangup sh loop »).

    Имя этого сигнала происходит не от казни через повешение, а от повешенной телефонной трубки.

    Источник

    Оцените статью