Detaillierte Erläuterung verschiedener Möglichkeiten zum Abrufen der PID (TID, LWP) von Linux-Threads

Detaillierte Erläuterung verschiedener Möglichkeiten zum Abrufen der PID (TID, LWP) von Linux-Threads

In Linux C/C++ werden Operationen auf Thread-Ebene normalerweise über die pthread-Bibliothek ausgeführt.

In der pthread-Bibliothek gibt es Funktionen:

pthread_t pthread_self(void);

Es gibt eine Variable vom Typ pthread_t zurück, die auf die „ID“ des Threads verweist, der die Funktion pthread_self aufgerufen hat.

Wie verstehen Sie diese „ID“?

Diese „ID“ ist die eindeutige Kennung innerhalb des Prozesses, die von der Pthread-Bibliothek für jeden Thread definiert wird und von der Pthread-Bibliothek verwaltet wird.

Da jeder Prozess seinen eigenen, unabhängigen Speicherplatz hat, ist der Gültigkeitsbereich dieser „ID“ auf Prozessebene und nicht auf Systemebene (der Kernel erkennt sie nicht).

Tatsächlich erstellt die pthread-Bibliothek auch Threads durch vom Kernel bereitgestellte Systemaufrufe (z. B. Klonen), und der Kernel erstellt für jeden Thread eine systemweit eindeutige „ID“, um den Thread eindeutig zu identifizieren.

Die global eindeutige „ID“ dieses Systems heißt Thread-PID (Prozess-ID) oder TID (Thread-ID) und wird auch LWP (Lightweight Process = Thread) genannt.

Wie kann ich die systemweit eindeutige „ID“ eines Threads im Kernel anzeigen? Man kann es grob in folgende Methoden unterteilen.

Testcode:

main.c

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void *start_routine(void *arg) {
 char msg[32] = "";
 snprintf(msg, sizeof(msg)-1, "thd%d: ich bin thd%d\n", *((int *)arg), *((int *)arg));
 während (1) {
 schreiben(1, msg, strlen(msg));
 Schlaf (1);
 }
}

int main() {

 Int th1 = 1;
 pthread_t tid1;
 pthread_create(&tid1, NULL, start_routine, &th1);

 int th2 = 2;
 pthread_t tid2;
 pthread_create(&tid2, NULL, start_routine, &th2);
 
 int th3 = 3;
 pthread_t tid3;
 pthread_create(&tid3, NULL, start_routine, &th3);

 const char *msg = "main: ich bin main\n";
 während (1) {
 schreiben(1, msg, strlen(msg));
 Schlaf (1);
 }

 gebe 0 zurück;
}

Im Hauptthread werden durch die pthread-Bibliothek drei Threads erzeugt, die kontinuierlich die Information „ich bin xxx“ ausgeben.

Laufende Ausgabe:

[test1280@localhost 20190227]$ gcc -o main main.c -lpthread
[test1280@localhost 20190227]$ ./main
main: ich bin main
thd2: ich bin thd2
thd3: ich bin thd3
thd1: ich bin thd1
thd2: ich bin thd2

Methode 1: ps -Lf $pid

[test1280@localhost ~]$ ps -Lf 11029
UID PID PPID LWP C NLWP STIME TTY STAT ZEIT CMD
test1280 11029 9374 11029 0 4 10:58 Punkte/0 Sl+ 0:00 ./main
test1280 11029 9374 11030 0 4 10:58 Punkte/0 Sl+ 0:00 ./main
test1280 11029 9374 11031 0 4 10:58 Punkte/0 Sl+ 0:00 ./main
test1280 11029 9374 11032 0 4 10:58 Punkte/0 Sl+ 0:00 ./main

11209 ist die PID des zu beobachtenden Prozesses.

Die Ausgabe zeigt, dass dieser Prozess 4 Threads enthält, ihre PIDs sind alle 11209 und ihre PPIDs sind alle 9374. LWP ist die Thread-ID, nach der wir suchen.

Wir haben festgestellt, dass es einen Thread gibt, dessen LWP mit der PID des Prozesses übereinstimmt, und dass es sich bei diesem Thread um den Hauptthread handelt.

-L Threads anzeigen, ggf. mit LWP- und NLWP-Spalten
-f führt eine Auflistung im Vollformat durch.

Methode 2: pstree -p $pid

[test1280@localhost ~]$ pstree -p 11029
Haupt(11029)─┬─{Haupt}(11030)
   ├─{main}(11031)
   └─{main}(11032)

Methode 3: top -Hp $pid

[test1280@localhost ~]$ top -Hp 11029 

Die Prozess-PID wird oben angegeben. Die Ausgabe enthält vier Threads. Das PID-Feld kann verwendet werden, um die PID (TID/LWP) jedes Threads abzurufen.

Mann oben
-H:Threads umschalten
Beginnt oben mit dem zuletzt gespeicherten umgekehrten „H“-Zustand.
Wenn dieser Schalter aktiviert ist, werden alle einzelnen Threads angezeigt.
Andernfalls wird oben eine Zusammenfassung aller Threads in einem Prozess angezeigt.
-p: PIDs überwachen

Methode 4: ls -l /proc/$pid/task/

[test1280@localhost ~]$ ls -l /proc/11029/task/
gesamt 0
dr-xr-xr-x. 6 test1280 test1280 0 27. Febr. 10:58 11029
dr-xr-xr-x. 6 test1280 test1280 0 27. Febr. 10:58 11030
dr-xr-xr-x. 6 test1280 test1280 0 27. Febr. 10:58 11031
dr-xr-xr-x. 6 test1280 test1280 0 27. Febr. 10:58 11032

Methode 5: pidstat -t -p $pid

[test1280@localhost ~]$ pidstat -t -p 11029
Linux 2.6.32-642.el6.x86_64 (localhost.localdomain) 27.02.2019 _x86_64_ (4 CPUs)

11:20:39 Uhr TGID TID %usr %system %guest %CPU CPU-Befehl
11:20:39 Uhr 11029 - 0,00 0,00 0,00 0,00 1 Haupt
11:20:39 Uhr - 11029 0,00 0,00 0,00 0,00 1 |__main
11:20:39 Uhr - 11030 0,00 0,00 0,00 0,00 1 |__main
11:20:39 Uhr - 11031 0,00 0,00 0,00 0,00 0 |__main
11:20:39 Uhr - 11032 0,00 0,00 0,00 0,00 3 |__main

TGID ist die Thread-Gruppen-ID. Die TID des Hauptthreads entspricht der Thread-Gruppen-ID des Hauptthreads, die wiederum der Prozess-ID des Prozesses entspricht, in dem sich der Hauptthread befindet.

man pidstat
-t Zeigt auch Statistiken für Threads an, die mit ausgewählten Aufgaben verknüpft sind.
 Diese Option fügt den Berichten die folgenden Werte hinzu:
 TGID: Die Identifikationsnummer des Thread-Gruppenleiters.
 TID: Die Identifikationsnummer des überwachten Threads.

Methode 6: Quellcode-Beschaffung

main.c

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/syscall.h>

pid_t gettid() {
 gibt Systemaufruf zurück (SYS_gettid);
}

void *start_routine(void *arg) {
 pid_t pid = gettid();
 pthread_t tid = pthread_self();
 printf("thd%d: pid=%d, tid=%lu\n", *((int *)arg), pid, tid);

 char msg[32] = "";
 snprintf(msg, sizeof(msg)-1, "thd%d: ich bin thd%d\n", *((int *)arg), *((int *)arg));
 während (1) {
 schreiben(1, msg, strlen(msg));
 Schlaf (1);
 }
}

int main() {

 pid_t pid = gettid();
 pthread_t tid = pthread_self();
 printf("main: pid=%d, tid=%lu\n", pid, tid);

 Int th1 = 1;
 pthread_t tid1;
 pthread_create(&tid1, NULL, start_routine, &th1);

 int th2 = 2;
 pthread_t tid2;
 pthread_create(&tid2, NULL, start_routine, &th2);
 
 int th3 = 3;
 pthread_t tid3;
 pthread_create(&tid3, NULL, start_routine, &th3);

 const char *msg = "main: ich bin main\n";
 während (1) {
 schreiben(1, msg, strlen(msg));
 Schlaf (1);
 }

 gebe 0 zurück;
}

Der Systemaufruf syscall(SYS_gettid) gibt einen Wert vom Typ pid_t zurück, der die ID des Threads im Kernel ist.

[test1280@localhost 20190227]$ gcc -o main main.c -lpthread
[test1280@localhost 20190227]$ ./main
Haupt: pid=11278, tid=140429854775040
main: ich bin main
thd3: pid=11281, tid=140429833787136
thd3: ich bin thd3
thd2: pid=11280, tid=140429844276992
thd2: ich bin thd2
thd1: pid=11279, tid=140429854766848
thd1: ich bin thd1
…

Was ist der Wert der PID (TID, LWP) eines Threads?

Die PID vieler Befehlsparameter bezieht sich tatsächlich auf die ID des Threads im Kernel, wie z. B. Taskset, Strace und andere Befehle.

Beispielsweise kann der Befehl „taskset“ einen Prozess an einen angegebenen CPU-Kern binden.

Wenn sich der Prozess im Multithread-Modus befindet, wird durch die direkte Verwendung des Tasksets nur der Hauptthread gebunden, andere Threads können nicht gebunden werden und werden nicht wirksam.

Beispiel:

# Binden Sie den Prozess 11282 an den CPU-Kern 0 [test1280@localhost ~]$ ps -Lf 11282
UID PID PPID LWP C NLWP STIME TTY STAT ZEIT CMD
test1280 11282 9374 11282 0 4 11:33 Punkte/0 Sl+ 0:00 ./main
test1280 11282 9374 11283 0 4 11:33 Punkte/0 Sl+ 0:00 ./main
test1280 11282 9374 11284 0 4 11:33 Punkte/0 Sl+ 0:00 ./main
test1280 11282 9374 11285 0 4 11:33 Punkte/0 Sl+ 0:00 ./main
[test1280@localhost ~]$ taskset -pc 0 11282
Aktuelle Affinitätsliste von pid 11282: 0-3
Neue Affinitätsliste von pid 11282: 0

# Prüfen, ob andere Threads wirklich an CPU-Kern 0 gebunden sind [test1280@localhost ~]$ taskset -pc 11283
Aktuelle Affinitätsliste von pid 11283: 0-3
[test1280@localhost ~]$ taskset -pc 11284
Aktuelle Affinitätsliste von pid 11284: 0-3
[test1280@localhost ~]$ taskset -pc 11285
Aktuelle Affinitätsliste von pid 11285: 0-3
[test1280@localhost ~]$ taskset -pc 11282
Aktuelle Affinitätsliste von pid 11282: 0
# Zu diesem Zeitpunkt ist tatsächlich nur der Hauptthread an den CPU-Kern 0 gebunden. # Binden Sie die anderen vier Threads an den CPU-Kern 0 [test1280@localhost ~]$ taskset -pc 0 11283
Aktuelle Affinitätsliste von pid 11283: 0-3
Neue Affinitätsliste von pid 11283: 0
[test1280@localhost ~]$ taskset -pc 0 11284
Aktuelle Affinitätsliste von pid 11284: 0-3
Neue Affinitätsliste von pid 11284: 0
[test1280@localhost ~]$ taskset -pc 0 11285
Aktuelle Affinitätsliste von pid 11285: 0-3
Neue Affinitätsliste von pid 11285: 0
# Ab diesem Zeitpunkt werden alle Threads des Prozesses mit Prozess-PID=11282 nur im CPU-Kern 0 ausgeführt

In ähnlicher Weise kann strace die Thread-PID angeben und die von einem Thread ausgeführten Systemaufrufe und Signale verfolgen.

Dies ist das Ende dieses Artikels über verschiedene Möglichkeiten, die PID (TID, LWP) eines Linux-Threads zu erhalten. Weitere Informationen zum Erhalten der PID eines Linux-Threads finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder durchsuchen Sie die folgenden verwandten Artikel weiter. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • So erhalten Sie PID basierend auf dem Prozessnamen in der Linux-Shell
  • Linux findet den vollständigen Pfad des Startprogramms anhand der Prozessnummer PID
  • Detaillierte Erläuterung des Wertebereichs von pid unter Linux-System
  • So finden Sie den entsprechenden Prozessnamen und das entsprechende Verzeichnis anhand der PID-Nummer in Linux
  • Detaillierte Erklärung der PID-Dateien im Verzeichnis /var/run/ unter Linux und ihrer Funktionen
  • Zusammenfassung der Verwendung des Linux-Befehls pidof
  • Linux erhält den Prozessnamen und die Prozess-PID basierend auf der PID (PID in der Sprache C abrufen)

<<:  Mybatis-Statistiken zur Ausführungszeit jeder SQL-Anweisung

>>:  Vue implementiert rekursiv benutzerdefinierte Baumkomponenten

Artikel empfehlen

Detaillierte Erläuterung der Anwendungsbeispiele für Vue-Router 4

Inhaltsverzeichnis 1. Installieren und erstellen ...

js, um einen einfachen Taschenrechner zu erstellen

In diesem Artikel finden Sie den spezifischen Cod...

Detaillierte Einführung in TABLE-Tags (TAGS)

Grundlegende Syntax der Tabelle <table>...&l...

Detaillierte Installation und Verwendung der Virtuoso-Datenbank unter Linux

Ich habe kürzlich einige Dinge zu verknüpften Dat...

JavaScript zum Hinzufügen und Löschen von Nachrichten im Message Board

Dieser Artikel zeigt ein kleines Beispiel für das...

SQL-Implementierung von LeetCode (184. Das höchste Gehalt der Abteilung)

[LeetCode] 184. Abteilung Höchstes Gehalt Die Mit...

So legen Sie die Breite und Höhe von HTML-Tabellenzellen fest

Beim Erstellen von Webseiten tritt häufig das Pro...

So verwenden Sie Nginx, um einen RTMP-Liveserver auszuführen

Dieses Mal haben wir einen RTMP-Liveübertragungss...

Detailliertes Tutorial zur Installation von ElasticSearch 6.4.1 auf CentOS7

1. Laden Sie das ElasticSearch 6.4.1-Installation...

Vue erhält Token zur Implementierung des Beispielcodes für die Token-Anmeldung

Die Idee hinter der Verwendung eines Tokens zur L...

Tipps zur Verwendung von Vue-Elementen und Nuxt

1. Konvertierung des Übermittlungsformats für die...

Vue+axios-Beispielcode zum Hochladen von Bildern und Erkennen von Gesichtern

Inhaltsverzeichnis Axios-Anfrage Qs-Verarbeitungs...

Ausführliche Erläuterung der Auswirkungen von NULL auf Indizes in MySQL

Vorwort Ich habe viele Blogs gelesen und von viel...