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.