LinuxスレッドのPID(TID、LWP)を取得するいくつかの方法の詳細な説明

LinuxスレッドのPID(TID、LWP)を取得するいくつかの方法の詳細な説明

Linux C/C++ では、スレッド レベルの操作は通常、pthread ライブラリを通じて実行されます。

pthread ライブラリには次の関数があります:

pthread_t pthread_self(void);

これは、pthread_self 関数を呼び出したスレッドの「ID」を参照する pthread_t 型の変数を返します。

この「ID」をどのように理解しますか?

この「ID」は、各スレッドの pthread ライブラリによって定義されるプロセス内の一意の識別子であり、pthread ライブラリによって管理されます。

各プロセスには独自の独立したメモリ空間があるため、この「ID」の範囲はシステム レベルではなくプロセス レベルになります (カーネルはこれを認識しません)。

実際、pthread ライブラリはカーネルが提供するシステム コール (clone など) を通じてスレッドを作成し、カーネルはスレッドを一意に識別するために各スレッドに対してシステム全体で一意の「ID」を作成します。

このシステムのグローバルに一意の「ID」は、スレッド PID (プロセス ID)、または TID (スレッド ID) と呼ばれ、LWP (軽量プロセス = スレッド) とも呼ばれます。

カーネル内のスレッドのシステム全体で一意の「ID」を表示するにはどうすればよいでしょうか?大きく分けて以下の方法があります。

テストコード:

メイン.c

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <文字列.h>
#include <unistd.h>
#include <pthread.h>

void *start_routine(void *arg) {
 char msg[32] = "";
 snprintf(msg, sizeof(msg)-1, "thd%d: i am thd%d\n", *((int *)arg), *((int *)arg));
 一方(1){
 書き込み(1, メッセージ, strlen(メッセージ));
 睡眠(1);
 }
}

int main() {

 整数 th1 = 1;
 tid1 はスレッドのインスタンスを生成する。
 pthread_create(&tid1, NULL, start_routine, &th1);

 整数 th2 = 2;
 pthread_tid2 の引数は tid2 です。
 pthread_create(&tid2, NULL, start_routine, &th2);
 
 整数 th3 = 3;
 pthread_tid3 の引数は、 tid3 です。
 pthread_create(&tid3, NULL, start_routine, &th3);

 const char *msg = "main: 私はメインです\n";
 一方(1){
 書き込み(1, メッセージ, strlen(メッセージ));
 睡眠(1);
 }

 0を返します。
}

メインスレッドでは、pthread ライブラリを通じて 3 つのスレッドが作成され、「i am xxx」という情報が継続的に出力されます。

実行出力:

[test1280@localhost 20190227]$ gcc -o main main.c -lpthread
[test1280@localhost 20190227]$ ./main
メイン:私はメインです
thd2: 私はthd2です
thd3: 私はthd3です
thd1: 私はthd1です
thd2: 私はthd2です

方法 1: ps -Lf $pid

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

11209 は監視対象のプロセスの PID です。

出力は、このプロセスに 4 つのスレッドが含まれており、それらの PID がすべて 11209、それらの PPID がすべて 9374 であることを示しています。LWP は、探しているスレッド ID です。

LWP がプロセスの PID と一致するスレッドがあり、そのスレッドがメイン スレッドであることに気付きました。

-L スレッドを表示します。LWP と NLWP の列も表示できます。
-f は完全形式のリストを表示します。

方法 2: pstree -p $pid

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

方法3: top -Hp $pid

[test1280@localhost ~]$ トップ -Hp 11029 

プロセス PID は top で指定されます。出力には 4 つのスレッドが含まれます。PID フィールドを使用して、各スレッドの PID (TID/LWP) を取得できます。

男のトップ
-H:スレッド切り替え
最後に記憶された「H」状態を反転した状態で上から開始します。
このトグルをオンにすると、すべての個別のスレッドが表示されます。
それ以外の場合、top はプロセス内のすべてのスレッドの合計を表示します。
-p: PIDを監視する

方法4: ls -l /proc/$pid/task/

[test1280@localhost ~]$ ls -l /proc/11029/task/
合計 0
dr-xr-xr-x. 6 test1280 test1280 0 2月27日 10:58 11029
dr-xr-xr-x. 6 test1280 test1280 0 2月27日 10:58 11030
dr-xr-xr-x. 6 test1280 test1280 0 2月27日 10:58 11031
dr-xr-xr-x. 6 test1280 test1280 0 2月27日 10:58 11032

方法5: pidstat -t -p $pid

[test1280@localhost ~]$ pidstat -t -p 11029
Linux 2.6.32-642.el6.x86_64 (localhost.localdomain) 2019 年 2 月 27 日 _x86_64_ (4 CPU)

11:20:39 AM TGID TID %usr %system %guest %CPU CPU コマンド
11:20:39 AM 11029 - 0.00 0.00 0.00 0.00 1 メイン
午前11:20:39 - 11029 0.00 0.00 0.00 0.00 1 |__メイン
午前11:20:39 - 11030 0.00 0.00 0.00 0.00 1 |__メイン
午前11:20:39 - 11031 0.00 0.00 0.00 0.00 0 |__メイン
午前11:20:39 - 11032 0.00 0.00 0.00 0.00 3 |__メイン

TGID はスレッド グループ ID です。メイン スレッドの TID は、メイン スレッドのスレッド グループ ID と同じであり、メイン スレッドが配置されているプロセスのプロセス ID と同じです。

男のピッドスタット
-t 選択したタスクに関連付けられているスレッドの統計も表示します。
 このオプションはレポートに次の値を追加します。
 TGID:スレッド グループ リーダーの識別番号。
 TID: 監視対象のスレッドの識別番号。

方法6: ソースコードの取得

メイン.c

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <文字列.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/syscall.h>

pid_t gettid() {
 syscall(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: i am thd%d\n", *((int *)arg), *((int *)arg));
 一方(1){
 書き込み(1, メッセージ, strlen(メッセージ));
 睡眠(1);
 }
}

int main() {

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

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

 整数 th2 = 2;
 pthread_tid2 の引数は tid2 です。
 pthread_create(&tid2, NULL, start_routine, &th2);
 
 整数 th3 = 3;
 pthread_tid3 の引数は、 tid3 です。
 pthread_create(&tid3, NULL, start_routine, &th3);

 const char *msg = "main: 私はメインです\n";
 一方(1){
 書き込み(1, メッセージ, strlen(メッセージ));
 睡眠(1);
 }

 0を返します。
}

syscall(SYS_gettid) システムコールは、カーネル内のスレッドの ID である pid_t 型の値を返します。

[test1280@localhost 20190227]$ gcc -o main main.c -lpthread
[test1280@localhost 20190227]$ ./main
メイン: pid=11278、tid=140429854775040
メイン:私はメインです
thd3: pid=11281、tid=140429833787136
thd3: 私はthd3です
thd2: pid=11280、tid=140429844276992
thd2: 私はthd2です
thd1: pid=11279、tid=140429854766848
thd1: 私はthd1です
…

スレッドの PID (TID、LWP) の値は何ですか?

多くのコマンド パラメータの PID は、実際には、taskset、strace、その他のコマンドなどのカーネル内のスレッドの ID を参照します。

たとえば、taskset コマンドは、プロセスを指定された CPU コアにバインドできます。

プロセスがマルチスレッド モードの場合、taskset を直接使用するとメイン スレッドのみがバインドされ、他のスレッドはバインドされず、有効になりません。

例:

# 11282 プロセスを CPU コア 0 にバインドします [test1280@localhost ~]$ ps -Lf 11282
UID PID PPID LWP C NLWP STIME TTY STAT TIME CMD
test1280 11282 9374 11282 0 4 11:33 pts/0 Sl+ 0:00 ./main
test1280 11282 9374 11283 0 4 11:33 pts/0 Sl+ 0:00 ./main
test1280 11282 9374 11284 0 4 11:33 pts/0 Sl+ 0:00 ./main
test1280 11282 9374 11285 0 4 11:33 pts/0 Sl+ 0:00 ./main
[test1280@localhost ~]$ タスクセット -pc 0 11282
pid 11282 の現在のアフィニティ リスト: 0-3
pid 11282 の新しいアフィニティ リスト: 0

# 他のスレッドが本当にCPUコア0にバインドされているかどうかを確認します [test1280@localhost ~]$ taskset -pc 11283
pid 11283 の現在のアフィニティ リスト: 0-3
[test1280@localhost ~]$ タスクセット -pc 11284
pid 11284 の現在のアフィニティ リスト: 0-3
[test1280@localhost ~]$ タスクセット -pc 11285
pid 11285 の現在のアフィニティ リスト: 0-3
[test1280@localhost ~]$ タスクセット -pc 11282
pid 11282 の現在のアフィニティ リスト: 0
# この時点では、メインスレッドのみが実際に CPU コア 0 にバインドされています。 # 他の 4 つのスレッドを CPU コア 0 にバインドします [test1280@localhost ~]$ taskset -pc 0 11283
pid 11283 の現在のアフィニティ リスト: 0-3
pid 11283 の新しいアフィニティ リスト: 0
[test1280@localhost ~]$ タスクセット -pc 0 11284
pid 11284 の現在のアフィニティ リスト: 0-3
pid 11284 の新しいアフィニティ リスト: 0
[test1280@localhost ~]$ タスクセット -pc 0 11285
pid 11285 の現在のアフィニティ リスト: 0-3
pid 11285 の新しいアフィニティ リスト: 0
# この時点で、プロセス PID=11282 のプロセスのすべてのスレッドは CPU コア 0 でのみ実行されます。

同様に、strace はスレッド PID を指定し、スレッドによって実行されたシステム コールとシグナルを追跡できます。

Linux スレッドの PID (TID、LWP) を取得するいくつかの方法についての記事はこれで終わりです。Linux スレッドの PID を取得する方法の詳細については、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Linux シェルでプロセス名に基づいて PID を取得する方法
  • Linuxはプロセス番号PIDに基づいて起動プログラムのフルパスを見つけます
  • Linuxシステムにおけるpidの値の範囲の詳細な説明
  • Linux で PID 番号から対応するプロセス名とディレクトリを見つける方法
  • Linux の /var/run/ ディレクトリにある pid ファイルとその機能の詳細な説明
  • Linux pidof コマンドの使用法の概要
  • Linuxはpidに基づいてプロセス名とプロセスpidを取得します(C言語でpidを取得します)

<<:  JS は VUE コンポーネントに基づいて都市リスト効果を実装します

>>:  Vueはカスタムツリーコンポーネントを再帰的に実装します

推薦する

Linux ディスクのマウント、パーティション分割、容量拡張操作を実装する方法

基本概念操作の前に、まずいくつかの基本的な概念を理解する必要がありますディスクLinux システムで...

JavaScript 操作要素の例

操作要素の詳細については、前回の記事を参照してください。JavaScript WebAPI、DOM、...

HTMLで細い線のテーブルを作成する簡単な例

この細線の表を作成する方法については、Baidu で検索すると、表に対して border="...

CSSはスクロールを許可しながらスクロールバーを非表示にするためにオーバーフローを設定します

CSS は、スクロールを許可しながらスクロール バーを非表示にするために Overflow を設定し...

MySQL 8.0.12 のインストールと設定方法のグラフィックチュートリアル

MySQL 8.0.12のインストールと設定方法を記録してみんなで共有します。 1. インストール1...

mysql インストーラ コミュニティ 8.0.16.0 のインストールと構成のグラフィック チュートリアル

mysqlインストーラコミュニティ8.0.16.0インストールグラフィックチュートリアル、参考までに...

MySql Group Byは複数のフィールドのグループ化を実装します

日常の開発タスクでは、データ テーブル内のグループ化フィールドに基づいて統計データを取得するために、...

Nginx の書き換え正規マッチング書き換え方法の例

Nginx の書き換え機能は、リダイレクトと同様に、URL アドレスを一時的または永続的に新しい場所...

jQuery を使用してカルーセル効果を実装する

この記事では、jQueryでカルーセルチャートを実装するための具体的なコードを参考までに共有します。...

CSS 完全な視差スクロール効果

1. 何ですか視差スクロールとは、複数の背景レイヤーを異なる速度で動かすことで、3次元のモーション...

Nginxの書き換えモジュールの詳細な説明

書き換えモジュールは ngx_http_rewrite_module モジュールです。その主な機能は...

C++ TpeScriptシリーズのジェネリックについて

目次1. テンプレート2. ジェネリック3. ジェネリック再帰4. デフォルトのジェネリックパラメー...

Vue3 の父子値転送に関する簡単な説明

目次父から息子へ: 1. 親コンポーネントのサブコンポーネントタグに、サブコンポーネントに渡されるデ...

OracleデータをMySQLデータベースに抽出する実装プロセス

Oracle データベースから MySQL データベースへの移行では、Oracle データベース モ...

js を使用して QR コードを生成するサンプル コード

以前、プロジェクトでQRコードをスキャンして情報を表示する機能を開発する必要がありました。インターネ...