Come rinominare tutti i thread (e i figli) di un processo su Linux?


22

Linux non segue (ancora) lo standard POSIX.1 che afferma che un reniceprocesso on influisce su "tutti i thread dell'ambito del sistema nel processo", perché secondo il documento pthreads (7) "i thread non condividono un buon valore comune".

Tuttavia, a volte, può essere conveniente renice"tutto" relativo a un determinato processo (un esempio potrebbe essere rappresentato dai processi figlio di Apache e da tutti i loro thread). Così,

  • come posso renicetutti i thread appartenenti a un determinato processo?
  • come posso renicetutti i processi figlio appartenenti a un determinato processo?

Sto cercando una soluzione abbastanza semplice.

So che i gruppi di processi a volte possono essere utili, tuttavia, non sempre corrispondono a ciò che voglio fare: possono includere un insieme più ampio o diverso di processi.

Anche l'uso di un cgroupgestito da systemdpotrebbe essere utile, ma anche se sono interessato a sentirlo, cerco principalmente una soluzione "standard".

EDIT: inoltre, man (7) pthreadsdice "tutti i thread in un processo sono inseriti nello stesso gruppo di thread; tutti i membri di un gruppo di thread condividono lo stesso PID". Quindi, è anche possibile renicequalcosa che non ha il proprio PID?

Risposte:


19

È possibile utilizzare /proc/$PID/taskper trovare tutti i thread di un determinato processo, quindi è possibile utilizzare

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

a renicetutti i thread appartenenti a un determinato processo.

Lo stesso modo /proc/$PID/task/$PID/childrenpuò essere utilizzato per trovare tutti i processi figlio (o /proc/$PID/task/*/childrense si desidera tutti i processi figlio di tutti i thread di un determinato processo).

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

man (7) pthreadsdice dell'attuale implementazione (NPTL): "tutti i thread in un processo sono collocati nello stesso gruppo di thread; tutti i membri di un gruppo di thread condividono lo stesso PID" e "I thread non condividono un valore comune". Quindi, come puoi rinominare un thread che non ha il proprio PID, quando reniceusa un PID per farlo?
— Totor

Ho provato renice su un ID thread e riporta 24995 (process ID) old priority 0, new priority -10. 24995 non appare in ps, quindi non è un processo. Forse i thread di reniceing funzionano davvero?
— Stefan Reich,

9

Buon valore o condivisioni CPU?

Si noti che al giorno d'oggi, i valori corretti potrebbero non essere così rilevanti "a livello di sistema", a causa del raggruppamento automatico di attività, soprattutto quando si utilizza systemd . Vedi questa risposta per maggiori dettagli.

Differenza tra thread e processi

Domanda importante su Linux, perché la documentazione perpetua i dubbi (ad esempio sui thread che non hanno il proprio PID).

Nota: questa risposta spiega con precisione i thread di Linux.

In breve: il kernel gestisce solo "entità eseguibili", ovvero qualcosa che può essere eseguito e programmato . Per quanto riguarda il kernel, queste entità sono chiamate processi. Un thread è solo un tipo di processo che condivide (almeno) lo spazio di memoria e gestisce i gestori del segnale con un altro.

Ogni processo di questo tipo ha un identificatore univoco a livello di sistema: il PID (Process ID). Per i cosiddetti thread, a volte viene chiamato TID (ID thread), ma dal punto di vista di sysadmin (e kernel!), TID e PID sono la stessa cosa (condividono lo stesso spazio dei nomi).

Di conseguenza, è possibile renice "thread" singolarmente perché hanno il proprio PID 1 .

Trovare tutti i PID in renice modo ricorsivo

Dobbiamo ottenere i PID di tutti i processi ("normali" o "thread") che sono discendenti (figli o nel gruppo di thread) del processo da definire. Questo dovrebbe essere ricorsivo (considerando i bambini dei bambini).

La risposta di Anton Leontiev dà il suggerimento per farlo: tutti i nomi delle cartelle in /proc/$PID/task/sono PID dei thread che contengono un childrenfile che elenca i potenziali processi figlio.

Tuttavia, manca di ricorsività, quindi ecco uno script di shell rapido e sporco per trovarli:

#!/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

Se il processo PID 1234 è quello che vuoi ricorsivamente bello, ora puoi fare:

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

1 Si noti che, per la conformità POSIX, la chiamata getpid(2)all'interno di un thread non fornirà l'ID univoco (PID) a livello di sistema di questa entità eseguibile, ma piuttosto il PID del processo principale all'interno del "gruppo di thread". Dovresti chiamare gettid(2)invece. Vedi questa risposta per maggiori informazioni.


6

Non dovremmo confondere il PID di processo e l'id thread a volte scritti TID o nel comando ps LPW. Il scomando ha opzioni per visualizzare i thread e sotto topo htopsi passa da thread a process dalla Hlettera. Come precedentemente detto da @Totor, con NPTL, che è l'implementazione corrente con kernel> 2.6, tutti i thread hanno lo stesso pid, ma hanno una tid distinta. Mostra tutti i thread di un processo tramite:

$ ps -Ljf <pid>

Questi tid sono i nomi delle directory sotto /proc/<pid>/task, e anche se renice (1) dice che il suo argomento predefinito è un pid quando applicato a un pid, rinomina solo il thread principale (questo è un bug nell'implementazione di Linux come scritto in setpriority (2) ) ), può anche essere applicato a una tid e azzera il thread. Ecco perché la risposta di @Anton è valida.

Ma molto spesso c'è un modo più semplice per ottenere il risultato desiderato, tutti questi thread condividono lo stesso pgid che è il pid del capogruppo; puoi renice con pgid emettendo:

$ renice -g <pgid>

Se non vuoi rinominare altri processi che dipendono dallo stesso capogruppo, devi usare la ricetta di @ Anton:

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

o:

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

Potresti anche voler sapere quali sono gli altri processi dello stesso gruppo rispetto al processo che vuoi rinominare, cioè i processi che condividono hanno lo stesso pgid. Puoi usare ps (1) , psnon ti permette di selezionare i processi per capogruppo, ma puoi grep a psper farlo. I processi con pgid 1908saranno dati dal comando:

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

o se preferisci awk a sed:

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

Questo non sembra funzionare correttamente su 4.19.4 (Debian Stretch al momento): $ 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;}' considerando che il metodo di Totor funziona / funziona ancora: $ /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 ... ho confermato con / proc, htop, pstree, ecc. Che ho il top- corretto PID di livello. Forse qualcosa è cambiato nell'ultimo anno.
— Bill McGonigle,

Non so come hai fatto il tuo test @ bill-mcgonigle, ho appena provato con tre kernel 4.9.0 su Debian Stretch; 4.18.0 e 4.19.0 su test Debian; E funziona come ho detto sopra.
— marcz,

Come ho detto, Debian Stretch su 4.19.4 con i comandi e l'output mostrati; la differenza sembra essere 4.19.0 contro 4.19.4 ma sono sorpreso che ci sarebbero molti cambiamenti tra queste versioni minori.
— Bill McGonigle,

Immagino che il tuo processo 8524 sia il PID di tutto il processo threaded TID o LPW, ma non il gruppo di processi, quindi ovviamente trovi tutti i thread /proc/8524/taskma renice -gfallisci. Quando si guarda un albero di processo, un ramo si trova nello stesso gruppo di processo, non solo un processo con thread. Riprova a controllare il risultato di ps -Ljf.
— marcz,

0

Vorrei raccomandare di usare l'argomento -g (process group) invece di -p (process id's) mentre si usa renice. Fa la stessa cosa senza il bash-foo.

vale a dire

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

La risposta di Marcz lo menziona già.
— Totor

-1

Ecco una mia sceneggiatura:

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

1
Questo avvia renice su tutti i processi tranne quello che hai nominato. Personalmente considero questo comando pericoloso e inadeguato.
— Totor

Mi chiedo se avesse significato -w not -v
— Diablo-D3
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.