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

CSS-Beispielcode zum Zeichnen eines Lutschers

Hintergrund: Machen Sie jeden Tag ein wenig Forts...

Grundlegende Anweisungen der MySQL-Datendefinitionssprache DDL

MySQL DDL-Anweisungen Was ist DDL, DML. DDL ist e...

Detaillierte Erklärung des MySQL-Covering-Index

Konzept Wenn der Index alle Daten enthält, die di...

Vue implementiert die vollständige Auswahlfunktion

In diesem Artikelbeispiel wird der spezifische Co...

Vergleichen von Dokumentspeicherorten

<br />Ein toller Blogbeitrag von PPK vor zwe...

So aktualisieren Sie die Knotenversion unter CentOs manuell

1. Suchen Sie das entsprechende NodeJS-Paket unte...

Detailliertes Tutorial zur Integration von Apache Tomcat mit dem IDEA-Editor

1. Laden Sie das komprimierte Tomcat-Paket von de...

Teilen Sie 8 CSS-Tools zur Verbesserung des Webdesigns

Wenn das Website-Design bearbeitet oder geändert ...

So entschlüsseln Sie Linux-Versionsinformationen

Das Anzeigen und Interpretieren von Informationen...

H-Tags sollten bei der Erstellung von Webseiten sinnvoll verwendet werden

HTML-Tags haben spezielle Tags zur Handhabung des ...

So schreiben Sie eine Node.JS-Version eines Spiels

Inhaltsverzeichnis Überblick Build-Prozess Verwan...

Der Implementierungsprozess der ECharts Multi-Chart-Verknüpfungsfunktion

Wenn viele Daten angezeigt werden müssen, ist die...

Der Vue.js-Cloud-Speicher realisiert die Bild-Upload-Funktion

Vorwort Tipp: Das Folgende ist der Hauptinhalt di...