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はカスタムツリーコンポーネントを再帰的に実装します

推薦する

UTF8 でエンコードされた Web ページにファイルが含まれている場合の、ページの前の空白行の解決方法

<br />このページはUTF8エンコードを使用しており、ヘッダーとフッターはテンプレー...

CSS3アニメーション属性に基づくWeChatタップアニメーション効果の実装

最近人気のWeChatタップ機能を見て、CSS3アニメーションを見直し、このボックスシェイクアニメー...

JS 1次元配列を3次元配列に変換する例

今日、CSDN の Q&A セクションで友人が質問をしているのを見ました。彼は 1 次元配列...

HTML H タイトルタグの使用

H タグ、特に h1 タグの使用は常に議論の的となっている問題であり、私たちが研究する価値のある問題...

MySQL binlog を使用して誤って削除されたデータベースを復元する方法

目次1 現在のデータベースの内容を表示し、データベースをバックアップする2 bin_log関数を有効...

CSS で TikTok テキスト揺れエフェクトを実装する例

日々の開発において、フロントエンドの学生はアニメーションやデザインについてよく議論します。デザイナー...

MySQL の遅いクエリの落とし穴

目次1. 遅いクエリ構成1-1. スロークエリを有効にする2. 遅いクエリSQLの分析を説明する3....

MySQL の同時実行性の問題と解決策の分析

目次1. 背景2. テーブルロックによるクエリの遅延3. オンラインでテーブル構造を変更するとどのよ...

@Font-face の基本的な使い方と、すべてのブラウザと互換性を持たせる方法

@Font-face 基本紹介: @font-face は、Web ページにカスタム フォントを表示...

Vue を使用して Web ページのスクリーンショットを撮る方法をご存知ですか?

目次1. html2Canvasをインストールする2. 必要なVueコンポーネントを導入する3. ス...

Linux 論理ボリューム管理 (LVM) の使用法の概要

ディスク領域の管理は、システム管理者にとって重要な日常的なタスクです。ディスク領域が使い果たされると...

VMware vSphere6.0 サーバー仮想化の展開とインストールの図 (詳細な手順)

1. VMware vSphere 導入の早期計画のポイント1. vSphereの利点(わずかに)...

React Nativeプロジェクトフレームワークの構築経験

React Native は、2015 年 4 月に Facebook によってオープンソース化され...

Vueバスの簡単な使い方

Vueバスの簡単な使い方シナリオの説明:コンポーネント A にはコンポーネント B と C が含まれ...

仕事の効率を上げるJS略語スキル20選

目次複数の変数を同時に宣言する場合は、1 行に短縮できます。分割代入は複数の変数に同時に値を割り当て...