Як відновити всі потоки (і діти) одного процесу в Linux?


22

Linux ще не дотримується стандарту POSIX.1, який говорить про те, що a reniceв процесі впливає на "всі потоки системи в процесі", оскільки згідно з документами pthreads (7) "потоки не мають загального приємного значення".

Однак іноді може бути зручно renice"все", пов'язане з певним процесом (одним із прикладів можуть бути дочірні процеси Apache та всі їх нитки). Так,

  • як я можу reniceвсі теми, що належать до певного процесу?
  • як я можу reniceвсі дочірні процеси, що належать до певного процесу?

Я шукаю досить просте рішення.

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

Використання cgroupкерованого by systemdтакож може бути корисним, але навіть якщо мені цікаво почути про це, я здебільшого шукаю «стандартне» рішення.

EDIT: також, man (7) pthreadsговорить, що "всі потоки в процесі розміщуються в одній групі потоків; всі члени групи потоків мають однаковий PID". Отже, чи можливо навіть reniceте, що не має власного PID?

Відповіді:


19

Ви можете використовувати /proc/$PID/taskдля пошуку всіх потоків заданого процесу, тому ви можете використовувати

$ ls /proc/$PID/task | xargs renice $PRIO

для reniceвсіх потоків, що належать даному процесу.

Цей же спосіб /proc/$PID/task/$PID/childrenможна використовувати для пошуку всіх дочірніх процесів (або, /proc/$PID/task/*/childrenякщо ви хочете, щоб усі дочірні процеси мали всі потоки заданого процесу).

$ cat /proc/$PID/task/$PID/children | xargs renice $PRIO
$ cat /proc/$PID/task/*/children | xargs renice $PRIO

man (7) pthreadsговорить про поточну реалізацію (NPTL): "всі потоки в процесі розміщуються в одній групі потоків; всі члени групи потоків мають однаковий PID" і "Нитки не мають спільного приємного значення". Потім, як можна відновити потік, який не має власного PID, коли для цього reniceвикористовується PID?
Тотор

Я спробував відновити ідентифікатор потоку, і він повідомляє 24995 (process ID) old priority 0, new priority -10. 24995 не відображається в ps, тому це не процес. Можливо, відновлює нитки насправді працює?
Стефан Рейх

9

Приємна вартість або акції CPU?

Зверніть увагу, що нині приємні значення можуть бути не настільки актуальними для загальної системи через автоматичне групування завдань, особливо при використанні systemd . Будь ласка, дивіться цю відповідь для отримання більш детальної інформації.

Різниця між потоками та процесами

Важливе питання щодо Linux, оскільки документація підтверджує сумніви (наприклад, у потоках немає власного PID).

Примітка: ця відповідь точно пояснює теми Linux.

Якщо коротко: ядро ​​обробляє лише "запущені об'єкти", тобто те, що можна запустити і запланувати . Ядро, ці сутності називають процесами. Потік - це лише певний процес, який ділиться (принаймні) простором пам'яті та обробниками сигналів з іншим.

Кожен такий процес має загальносистемний унікальний ідентифікатор: PID (ідентифікатор процесу). Для так званих потоків його іноді називають TID (ідентифікатор теми), але з точки зору sysadmin (і ядро!), TID і PID - це одне і те ж (вони мають одне і те саме простір імен).

Як результат, ви можете renice кожен "потік" окремо, оскільки у них є власний PID 1 .

Пошук усіх PID- renice рекурсивно

Нам потрібно отримати ПІД усіх процесів ("нормальних" або "потокових"), які є нащадками (діти або в групі потоків) процесу, що має бути визначений. Це повинно бути рекурсивним (враховуючи дітей дітей).

Відповідь Антона Леонтьєва дає натяк на це: усі назви папок /proc/$PID/task/- це PID-потоки, що містять childrenфайл, у якому перераховані потенційні дочірні процеси.

Однак йому не вистачає рекурсивності, тому ось швидкий та брудний сценарій оболонки, щоб знайти їх:

#!/bin/sh
[ "$#" -eq 1 -a -d "/proc/$1/task" ] || exit 1

PID_LIST=
findpids() {
        for pid in /proc/$1/task/* ; do
                pid="$(basename "$pid")"
                PID_LIST="$PID_LIST$pid "
                for cpid in $(cat /proc/$1/task/$pid/children) ; do
                        findpids $cpid
                done
        done
}

findpids $1
echo $PID_LIST

Якщо процес PID 1234 - той, який ви хочете рекурсивно приємно, тепер ви можете зробити:

renice -n 15 -p $(/path/to/findchildren.sh 1234)

1 Зауважте, що для відповідності POSIX виклик getpid(2)всередині потоку не дасть вам загальносистемного унікального ідентифікатора (PID) цього об'єкта, що виконується, а швидше PID основного процесу в "групі потоків". Вам потрібно буде зателефонувати gettid(2)замість цього. Дивіться цю відповідь для отримання додаткової інформації.


6

Ми не повинні плутати PID процесу та ідентифікатор потоку колись написаний TID або в команді ps LPW. sКоманда має опції для відображення потоків, і під topабо htopперемикатися між потоками і процесом в Hлисті. Як раніше розповідав @Totor, з NPTL, яка є поточною реалізацією з ядром> 2.6, всі потоки мають однаковий pid, але вони мають чітку підкладку. Ви показуєте всі потоки процесу:

$ ps -Ljf <pid>

Ці тиди - це назви каталогів /proc/<pid>/task, і навіть якщо renice (1) говорить про те, що аргумент за замовчуванням є pid при застосуванні до pid, він відновлює лише основний потік (це помилка в реалізації Linux, як написано в setpriority (2 ) ), він також може бути застосований до відливу і відновлює нитку. Ось чому відповідь @Anton справедлива.

Але найчастіше існує простіший спосіб досягти бажаного результату, всі ці потоки поділяють той самий pgid, який є pid керівника групи; ви можете відновити їх за допомогою pgid, видавши:

$ renice -g <pgid>

Якщо ви не хочете відновлювати якийсь інший процес, який залежить від того самого керівника групи, вам потрібно скористатися рецептом @ Антона:

$ renice <priority> $(ls -1 /proc/<pid>/task)

або:

$renice <priority> $(ps --no-header -Lo tid <pid>)

Ви також можете дізнатися, що є інші процеси тієї самої групи, ніж процес, який ви хочете відновити, тобто процеси, які мають спільний доступ, мають однаковий pgid. Ви можете використовувати ps (1) , psщо не дозволяє вибирати процеси за лідером групи, але ви можете psзробити це для цього. Процеси з pgid 1908будуть задані командою:

$ ps --no-header axo pid,pgid |sed -n '/^ *[0-9][0-9]*  *1908/s/[0-9][0-9]* *$//p'

або якщо ви віддаєте перевагу awk to sed:

$ ps --no-header axo pid,pgid|awk '{if ($2=="1908") print $1;}'

Схоже, це не працює правильно в 4.19.4 (Debian Stretch відтепер): В $ renice -n 18 -g 8524 renice: failed to get priority for 8524 (process group ID): No such process $ ps --no-header axo pid,pgid|awk '{if ($2=="8524") print $1;}' той час, як метод Тотора працює / все ще працює: $ /bin/ls /proc/8524/task | /usr/bin/xargs renice 19 2739 (process ID) old priority 19, new priority 19 2740 (process ID) old priority 19, new priority 19 ... я підтвердив за допомогою / proc, htop, pstree тощо, що у мене є правильний верхній- рівень PID. Можливо, щось змінилося за останній рік.
Білл МакГонігле

Я не знаю, як ви зробили тест @ bill-mcgonigle, я просто спробував три ядра 4.9.0 на Debian Stretch; 4.18.0 та 4.19.0 про тестування Debian; І це працює, як я говорив вище.
березня

Як я вже говорив, Debian Stretch 4.19.4 із показаними командами та висновками; різниця, здається, становить 4,19,0 проти 4,19,4, але я здивований, що між такими незначними версіями буде багато змін.
Білл МакГонігле

Я здогадуюсь, що ваш процес 8524 - це PID всіх потокових процесів TID або LPW, але не група процесів, тому, звичайно, ви знайдете всі потоки, /proc/8524/taskале renice -gне вийшли з ладу. Коли ви дивитесь на дерево процесів, одна гілка знаходиться в одній групі процесів, а не лише один процес з потоком. Спробуйте ще раз перевірити результат ps -Ljf.
березень

0

Я хотів би рекомендувати використовувати аргумент -g (групи процесів) замість -p (ідентифікатори процесу) під час використання renice. Це те ж саме робить і без баш-фу.

тобто

(sudo) renice -n <NEW_PRIORITY> -g <MAIN_PROCESS_ID>

Відповідь марчі вже згадує про це.
Тотор

-1

Ось мій сценарій:

pgrep -v <PROCESS_NAME> | sudo xargs renice <NEW_PRIORITY>

1
Це запускає реніке на всіх процесах, крім того, який ви назвали. Я особисто вважаю цю команду небезпечною та неадекватною.
Тотор

Цікаво, чи мав він на увазі -w not -v
Diablo-D3
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.