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

推薦する

MySQL最新バージョン8.0.17解凍版インストールチュートリアル

個人的にはインストール版よりも解凍版の方がインストールしやすいと思います。早速、解凍版のインストール...

WeChatアプレットの入力レベルとテキストエリアレベルの浸透率が高すぎる問題の解決策

WeChat ミニプログラムのネイティブ コンポーネントであるカメラ、キャンバス、入力 (フォーカス...

Bツリーの特性の紹介

B ツリーは一般的なデータ構造です。彼と一緒にB+ツリーがあります。ここで、概念を明確にする必要があ...

Vueでファジークエリを実装する方法の簡単な例

序文いわゆるファジークエリとは、ユーザーの完全な入力やすべての入力情報がなくてもクエリサービスを提供...

MySQLデータベースがNULLを可能な限り避ける理由

MySQL の多くのテーブルには、NULL が列のデフォルト属性であるため、アプリケーションが NU...

HTMLがHikvisionカメラのリアルタイム監視機能を実現

最近、同社は CCFA 関連のいくつかの作業を行う予定で、その 1 つはカメラのリアルタイム監視を再...

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

圧縮パッケージのインストールは、mysql-5.7 以降、大幅に変更されました。この記事では、mys...

Docker ベースの ELK を素早く構築する方法

[概要] この記事では、自作の Docker プラットフォームをベースに完全な ELK システムを素...

アイデアがWebプロジェクトを公開した後、Tomcatサーバーがプロジェクトとそのソリューションを見つけることができません

概要プロジェクトは正常に作成され、正常にデプロイされましたが、以下に示すように、Tomcat サーバ...

MySQL の中国語ソートの詳細と例

MySQL の漢字ソートの詳細な説明デフォルトでは、MySQL は日付、時刻、および英語の文字列の並...

超シンプルな QPS 統計手法 (推奨)

過去 N 秒間の QPS 値の統計 (1 秒あたりの選択、挿入などを含む) mysql> se...

MySQLはパスワードなしでログインする例を実装しています

具体的な方法:ステップ1: mysqlサービスを停止する /etc/init.d/mysqld を停...

React forwardRefの使い方と注意点

これまで react.forwardRef は react の高階コンポーネントには適用できませんで...

ボタンと入力タイプの違いと注意点

<button> タグ<br />定義と使用法<button> ...

JSプロトタイプとプロトタイプチェーンについての簡単な説明

目次1. プロトタイプ2. プロトタイプポインタ: __proto__要約する1. プロトタイプJa...