Wie kann ich alle Threads (und untergeordneten) eines Prozesses unter Linux erneut ausführen?

22

Linux folgt (noch) nicht dem POSIX.1-Standard, der besagt, dass ein reniceOn-Prozess "alle System-Scope-Threads im Prozess" betrifft, da laut pthreads (7) doc "Threads keinen gemeinsamen Nice-Wert haben".

Manchmal kann es jedoch praktisch sein, renice"alles" zu tun, was sich auf einen bestimmten Prozess bezieht (ein Beispiel wären untergeordnete Apache-Prozesse und alle ihre Threads). So,

  • Wie kann ich renicealle Threads, die zu einem bestimmten Prozess gehören?
  • Wie kann ich renicealle untergeordneten Prozesse, die zu einem bestimmten Prozess gehören, ausführen?

Ich suche eine ziemlich einfache Lösung.

Ich weiß, dass Prozessgruppen manchmal hilfreich sein können, aber sie stimmen nicht immer mit meinen Vorstellungen überein: Sie können eine breitere oder andere Gruppe von Prozessen umfassen.

Die Verwendung einer von cgroupverwalteten systemdSoftware kann ebenfalls hilfreich sein, aber selbst wenn ich daran interessiert bin, etwas darüber zu erfahren, suche ich meistens nach einer "Standard" -Lösung.

BEARBEITEN: man (7) pthreadssagt auch, dass "alle Threads in einem Prozess in derselben Thread-Gruppe platziert werden; alle Mitglieder einer Thread-Gruppe haben dieselbe PID". Ist es also überhaupt möglich, reniceetwas zu tun, das keine eigene PID hat?

Totor
quelle

Antworten:

19

Sie können verwenden /proc/$PID/task, um alle Threads eines bestimmten Prozesses zu finden, daher können Sie verwenden

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

auf renicealle Threads, die zu einem bestimmten Prozess gehören.

Auf die gleiche Weise /proc/$PID/task/$PID/childrenkönnen Sie alle untergeordneten Prozesse finden (oder /proc/$PID/task/*/childrenalle untergeordneten Prozesse aller Threads eines bestimmten Prozesses).

$ cat /proc/$PID/task/$PID/children | xargs renice $PRIO
$ cat /proc/$PID/task/*/children | xargs renice $PRIO
Anton Leontiev
quelle
man (7) pthreadssagt über die aktuelle (NPTL-) Implementierung: "Alle Threads in einem Prozess werden in dieselbe Thread-Gruppe gestellt; alle Mitglieder einer Thread-Gruppe haben dieselbe PID" und "Threads haben keinen gemeinsamen Wert". Wie können Sie dann einen Thread, der keine eigene PID hat, umbenennen, wenn Sie dazu reniceeine PID verwenden?
Totor
Ich habe versucht, Renice auf einem Thread-ID, und es berichtet 24995 (process ID) old priority 0, new priority -10. 24995 erscheint nicht in ps, es ist also kein Prozess. Vielleicht funktioniert es tatsächlich, Threads zu erneuern?
Stefan Reich
9

Guter Wert oder CPU-Anteile?

Bitte beachten Sie, dass nette Werte heutzutage möglicherweise "systemweit" nicht mehr so ​​relevant sind, da die Aufgaben automatisch gruppiert werden, insbesondere wenn systemd verwendet wird . Bitte lesen Sie diese Antwort für weitere Details.

Unterschied zwischen Threads und Prozessen

Wichtige Frage zu Linux, da die Dokumentation Zweifel aufkommen lässt (zum Beispiel über Threads ohne eigene PID).

Hinweis: Diese Antwort erklärt Linux-Threads genau.

Kurz gesagt: Der Kernel verarbeitet nur "ausführbare Entitäten", dh solche, die ausgeführt und geplant werden können . Kerneltechnisch werden diese Entitäten Prozesse genannt. Ein Thread ist nur eine Art Prozess, der (mindestens) Speicherplatz und Signalhandler mit einem anderen teilt.

Jeder dieser Prozesse hat eine systemweit eindeutige Kennung: die PID (Process ID). Bei sogenannten Threads wird es manchmal als TID (Thread ID) bezeichnet, aber aus der Sicht von Sysadmin (und Kernel!) Sind TID und PID dasselbe (sie haben denselben Namespace).

Als Ergebnis Sie können renice jeden „Faden“ einzeln , weil sie ihre eigene PID 1 .

Ermitteln aller PIDs zu renice rekursiv

Wir müssen die PIDs aller Prozesse ("normal" oder "thread") abrufen, die vom zu prüfenden Prozess abstammen (untergeordnete Prozesse oder in der Thread-Gruppe). Dies sollte rekursiv sein (unter Berücksichtigung der Kinder von Kindern).

Die Antwort von Anton Leontiev gibt den Hinweis, dies zu tun: Alle Ordnernamen in /proc/$PID/task/sind die PID von Threads, die eine childrenDatei enthalten, in der potenzielle untergeordnete Prozesse aufgelistet sind.

Da es jedoch keine Rekursivität gibt, finden Sie hier ein schnelles und unsauberes Shell-Skript, um diese zu finden:

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

Wenn der Prozess PID 1234 derjenige ist, den Sie rekursiv verwenden möchten, können Sie jetzt Folgendes tun:

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

1 Beachten Sie, dass aus Gründen der POSIX-Konformität beim Aufrufen getpid(2)innerhalb eines Threads nicht die systemweit eindeutige ID (PID) dieser ausführbaren Entität, sondern die PID des Hauptprozesses innerhalb der "Thread-Gruppe" angegeben wird. Sie müssten gettid(2)stattdessen anrufen . Weitere Informationen finden Sie in dieser Antwort .

Totor
quelle
6

Wir sollten die Prozess-PID und die Thread-ID nicht verwechseln, wenn TID oder der ps-Befehl LPW geschrieben wurde. Der sBefehl verfügt über Optionen zum Anzeigen von Threads und unter topoder htopSie wechseln zwischen Threads und verarbeiten nach dem HBuchstaben. Wie @Totor zuvor mit NPTL, der aktuellen Implementierung mit Kernel> 2.6, mitteilte, haben alle Threads die gleiche pid, aber eine unterschiedliche tid. Sie zeigen alle Threads eines Prozesses durch:

$ ps -Ljf <pid>

Diese tid sind die Namen der Verzeichnisse unter /proc/<pid>/task, und selbst wenn renice (1) sagt, dass sein Standardargument eine pid ist, wenn es auf eine pid angewendet wird, wird nur der Hauptthread renice (dies ist ein Fehler in der Linux-Implementierung, wie in setpriority (2) geschrieben) ) ), es kann auch auf ein Tid angewendet werden und es ändert den Thread. Deshalb ist die Antwort von @Anton gültig.

Meistens ist es jedoch einfacher, das gewünschte Ergebnis zu erzielen. Alle diese Threads haben dieselbe pgid, die die pid des Gruppenleiters ist. Sie können durch pgid durch Ausgabe von renice:

$ renice -g <pgid>

Wenn Sie einen anderen Prozess, der von demselben Gruppenleiter abhängt, nicht erneut ausführen möchten, müssen Sie das Rezept von @ Anton verwenden:

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

oder:

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

Möglicherweise möchten Sie auch wissen, welche anderen Prozesse derselben Gruppe zu dem Prozess gehören, den Sie erneut ausführen möchten. Dies sind die Prozesse, die dieselbe pgid für die Freigabe haben. Sie können ps (1) verwenden , pserlaubt es nicht, Prozesse nach Gruppenleiter auszuwählen, aber Sie können a bitten ps, dies zu tun. Die Prozesse mit pgid 1908werden durch den Befehl angegeben:

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

oder wenn Sie es vorziehen awk zu sed:

$ ps --no-header axo pid,pgid|awk '{if ($2=="1908") print $1;}'
marcz
quelle
Dies scheint unter 4.19.4 (Debian Stretch ab sofort) nicht richtig zu funktionieren: $ 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;}' Während Totors Methode funktioniert / immer noch funktioniert: $ /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 ... Ich habe mit / proc, htop, pstree usw. bestätigt, dass ich die richtige Top-Version habe. Level PID. Vielleicht hat sich im letzten Jahr etwas geändert.
Bill McGonigle
Ich weiß nicht, wie Sie Ihren Test @ bill-mcgonigle gemacht haben, ich habe es gerade mit drei Kerneln 4.9.0 auf Debian Stretch versucht; 4.18.0 und 4.19.0 unter Debian-Tests; Und es funktioniert wie oben gesagt.
12.
Wie ich bereits sagte, Debian Stretch unter 4.19.4 mit den gezeigten Befehlen und Ausgaben; Der Unterschied scheint 4.19.0 zu 4.19.4 zu sein, aber ich bin überrascht, dass sich zwischen solchen Nebenversionen viel ändern würde.
Bill McGonigle
Ich nehme an, Ihr Prozess 8524 ist die PID aller Thread-Prozess-TIDs oder LPWs, aber nicht die Prozessgruppe. Natürlich finden Sie alle Threads in, /proc/8524/taskaber renice -gschlagen fehl. Wenn Sie sich einen Prozessbaum ansehen, befindet sich ein Zweig in derselben Prozessgruppe und nicht nur ein Thread-Prozess. Versuchen Sie erneut, das Ergebnis von zu überprüfen ps -Ljf.
17.
0

Ich würde empfehlen, das Argument -g (Prozessgruppen) anstelle von -p (Prozess-IDs) zu verwenden, wenn Sie renice verwenden. Es macht dasselbe ohne das Bash-Foo.

dh

(sudo) renice -n <NEW_PRIORITY> -g <MAIN_PROCESS_ID>
user12042
quelle
In der Antwort von marcz wird dies bereits erwähnt.
Totor
-1

Hier ist ein Skript von mir:

pgrep -v <PROCESS_NAME> | sudo xargs renice <NEW_PRIORITY>
Antonio Petricca
quelle
1
Dadurch wird bei allen Prozessen außer dem von Ihnen benannten ein Neustart ausgeführt. Ich persönlich halte diesen Befehl für gefährlich und unangemessen.
Totor
Ich frage mich, ob er -w nicht -v
Diablo-D3