Можно ли временно приостановить процесс в Linux?

53

Мне было интересно, есть ли способ заморозить какой-либо процесс на определенное время?

Я имею в виду следующее: возможно ли, чтобы одно приложение (возможно, работающее от имени пользователя root) приостановило выполнение другого уже запущенного процесса (любого процесса, как с графическим интерфейсом, так и из командной строки), а затем возобновило его позже? Другими словами, я не хочу, чтобы определенные процессы планировались планировщиком Linux на определенное время.

Pal Szasz
источник

Ответы:

81

Смотри здесь

Есть два сигнала, которые могут приостановить выполнение процесса. Один «грациозен», а другой «силен».

«Изящный» - это один SIGTSTP, и его цель состоит в том, чтобы «приятно» попросить процесс, если ему это нравится, приостановить выполнение, пока не получит a SIGCONT. В случае SIGTSTP, процесс может игнорировать SIGTSTP и продолжить выполнение в любом случае, так что это требует сотрудничества со стороны программы, которая предназначена для обработки SIGTSTP.

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

Чтобы отправить произвольный сигнал, в том числе и любой из них , упомянутых здесь, вы можете использовать программы , такие как kill, killallили pkill; или используйте системный вызов kill(2). Обратитесь к руководствам вашей операционной системы, чтобы узнать подробности, связанные с платформой / архитектурой / версией, и сведениями, касающимися любого из перечисленного Обратите внимание, что слово «kill» во всех этих командах и системном вызове является неправильным. Эти команды не предназначены исключительно для завершения процессов. Они могут сделать это, отправив определенные сигналы; но сигналы также могут использоваться для других функций, кроме завершения процесса. Например, SIGSTOPтолько приостанавливает процесс, и это только один из нескольких сигналов, которые могут быть отправлены таким образом.

Чтобы добавить условие автоматического возобновления процесса по истечении определенного периода времени, вам нужно будет использовать какой-то процесс мониторинга, который остается запущенным и устанавливает таймер, чтобы активировать процесс мониторинга, который затем, в свою очередь, вызывает kill(2)и отправляет SIGCONTсигнал остановленному процессу, чтобы запросить ядро ​​возобновить выполнение. Обратите внимание, что в Linux есть несколько механизмов синхронизации с различной степенью точности; Более того, если ваша система очень занята, ваш процесс мониторинга может не проснуться до тех пор, пока не истечет его таймер, и, следовательно, пробуждение может быть отложено.

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

Вы не указали, какие технологии вы хотите использовать для реализации этого. Как минимум, вам понадобится, по крайней мере, сценарий bash, хотя вы не сможете получить очень точную синхронизацию таким образом. Вот bash-скрипт (непроверенный, поэтому, пожалуйста, будьте осторожны), который является просто доказательством концепции вашего запроса. Если вам нужно точное время, вам придется написать программу, возможно на C / C ++ или другом родном языке, и использовать планирование в реальном времени и hrtimers.

#!/bin/bash
#This is the process you want to suspend.
screen -mdS child bash -c "cat /dev/urandom | base64"
#This is the process ID of the child process
THEPID=$(screen -list | grep child | cut -f1 -d'.' | sed 's/\W//g')
#Send SIGSTOP to the child process.
kill -SIGSTOP ${THEPID}
#Now it is suspended. This process will sleep for 10 seconds asynchronously, then resume the process.
screen -mdS monitor bash -c "sleep 10; kill -SIGCONT ${THEPID}"

Обратите внимание, что сценарий завершится, а управляющий сценарий завершится, но из-за screenуправления процессом монитора он продолжит работать в фоновом режиме в течение 10 секунд (на основе переданного аргумента sleep), а затем активируется и продолжит дочерний процесс. Но это будет долго после того, как управляющий скрипт закончится. Если вы хотите синхронно ждать истечения времени, просто пропустите второй вызов screenи жестко закодируйте сон и уничтожение в управляющем скрипте.

Вы можете проверить, что процесс на самом деле приостанавливается, запустив

screen -rS child

после запуска этого скрипта. Вы не увидите ничего на консоли. Затем, после истечения таймера (10 секунд), он заполнит ваш экран данными base64 (случайные символы от 0 до 9 и AF). Нажмите Ctrl + C, чтобы выйти.

allquixotic
источник
Очень хороший, очень полный ответ, включая фрагмент кода PoC. Приятно!
fgysin
Если процесс зависает в середине сетевого сеанса, например TCP-соединения, когда он продолжается, может ли этот сетевой сеанс быть поврежден или прерван? Есть ли определенное поведение для этого?
CMCDragonkai
@cmcdragonkai, потому что, поскольку остановленный процесс не запущен, он не может читать или записывать данные на любой fd, но ядро ​​продолжает передавать байты до тех пор, пока его буфер не будет заполнен во время сеанса TCP, то есть нет передачи между пространством ядра и пространством пользователя. Процессы замораживания - это другая проверка https://www.kernel.org/doc/Documentation/power/freezing-of-tasks.txt
Низам Мохамед,
Я обнаружил, что соединения TCP могут продолжаться после возвращения процесса на передний план (таймауты зависят от приложения, есть поддержка активности TCP, но также поддержка активности на уровне приложения). Процессы зависания, кажется, означают, когда компьютер находится в режиме гибернации или в спящем режиме. Это правильно?
CMCDragonkai
Этот сценарий не влияет на некооперативные коды: gist.github.com/ceremcem/864dd94b52ffe7b18da29558df4f1f5b
ceremcem
14

Да, вы можете сделать это, отправив сигнал STOP процессу, чтобы приостановить его, а затем CONT, чтобы продолжить.

использование:

kill -STOP <pid>

kill -CONT <pid>

источник
11

Если у вас есть достаточно свободное определение «заморозить», вы можете проверить reniceкоманду.

Renice позволяет изменить приоритет планирования запущенных процессов.

Обычное значение nice процесса равно 0. Увеличение значения nice делает процесс более приятным, как в «Почему бы вам не пойти первым». В то время как уменьшение значения nice делает процесс менее приятным, например, «убирайся с дороги, я спешу». Хороший диапазон значений от -20 до 19.

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

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

Вот пример запуска на моей локальной машине Linux.

Используйте ps -lи посмотрите на столбец NI, чтобы увидеть хорошее значение для процесса.

-> пс-л
FS UID PID PPID C PRI NI ADDR SZ WCHAN TTY CMD
0 S 29190 402 31146 0 75 0 - 16547 wait pts / 0 bash
0 T 29190 1105 402 0 75 0 - 23980 ф / к 0 vim
0 R 29190 794 402 0 76 0 - 15874 - pts / 0 ps

Запуск renice +10процесса vim приводит к тому, что он запускается с более низким приоритетом.

-> Ренис +10 -p 1105
1105: старый приоритет 0, новый приоритет 10

-> пс-л
FS UID PID PPID C PRI NI ADDR SZ WCHAN TTY CMD
0 S 29190 402 31146 0 76 0 - 16547 wait pts / 0 bash
0 T 29190 1105 402 0 95 10 - 23980 ф / к 0 vim
0 R 29190 1998 402 0 78 0 - 15874 - pts / 0 ps

Предполагая, что вы можете растянуть «заморозить», чтобы означать «не беспокоить кого-либо еще в системе», вы можете написать что-то вроде:

ренис 20-р <пид процентов>
спать <определенное количество времени>
ренис 0-р <пид процентов>

(не забудьте запустить его как root).


обратите внимание, что я взял некоторые вольности с приведенным выше ps -lвыводом, чтобы интересные столбцы хорошо отображались в маленьких синих прямоугольниках :)

Морис
источник