プロセスとスレッド
同じ実行ファイルから動く処理を、PID・TID・アドレス空間で整理します。
説明
プロセスは実行中のプログラムの管理単位で、スレッドはその中で命令を実行する流れです。同じプロセスのスレッドはメモリやファイル記述子を共有し、実行位置やスタックは個別に持ちます。
二つのworkerプロセスを記録した表を使い、プロセス数とスレッド数、共有されるメモリ、各スレッドのスタックを調べます。最後にPIDが再利用された履歴を絞り込み、別の実行を混同しない条件を確かめます。
1プロセスと実行中のスレッド
tasks.csvはLinuxのプロセスとスレッドを整理した教材用の表です。PIDはプロセス、TIDはスレッド、PPIDは親プロセスを識別します。VMとFD_TABLEには共有範囲が分かるように記号を付けています。
cat一覧を表示 tasks.csvプロセスとスレッドの対応PID210にはTID210と211の二つのスレッドがあり、仮想アドレス空間Aとファイル記述子表F1を共有します。PID310もworkerですが、別のアドレス空間Bと表F2を持ちます。実行ファイル名だけでは同じプロセスか判断できません。
2プロセス数とスレッド数
PIDを重複なく数えた場合と、TIDの行を数えた場合を比べます。ヘッダー行は除きます。
awk -F, 'NR>1 {print $1}' tasks.csvPID列 | sort -u重複を除く | wc -lプロセス数; awk -F, 'NR>1 {n++} END {print n}' tasks.csvスレッドの行数プロセスは2個、スレッドは3個です。Sは待ち状態、Rは実行中または実行可能な状態を表します。プロセスが存在することと、その瞬間にCPU上で命令を実行していることは別です。
3同じアドレスでも値が違う場合
memory.csvは仮想アドレス空間ごとの値を示します。0x4000という同じ数値のアドレスを抽出します。
awk -F,メモリ表を読む 'NR==1 || $2=="0x4000"'指定アドレスの行 memory.csv空間別の内容空間Aでは10、空間Bでは90です。別プロセスの同じ仮想アドレスが、同じ物理メモリを指すとは限りません。一方、同一プロセス内の二つのスレッドはAの0x4000を共通に参照します。
4片方のスレッドが共有領域を書き換える
TID211がAの0x4000へ11を書いた後の表を作ります。空間とアドレスの両方を指定し、元の表を残します。
awk -F,CSVを編集 'BEGIN {OFS=FS} $1=="A" && $2=="0x4000" {$3=11} {print}'Aの指定位置だけ変更 memory.csv > after.csv別の表へ保存; cat after.csv変更後の内容空間Aだけが11になり、Bは90のままです。Aを共有するTID210からも同じ保存先の値を参照できます。ただし複数スレッドが同時に読み書きする実際のプログラムでは、言語やCPUのメモリモデルに従った同期が必要です。
5各スレッドのスタック
スタックは関数呼出しや局所変数の保持に使います。REGION列から各スレッド用の範囲を取り出します。
awk -F,領域名で選別 'NR==1 || $4 ~ /stack/'スタックの行 after.csv変更後のメモリ表TID210と211のスタックは別の位置ですが、どちらも同じアドレス空間Aの中です。「スレッド専用のスタック」は用途が別という意味で、他スレッドからアドレスを使って一切アクセスできない保護領域という意味ではありません。CPUレジスタの実行状態もスレッドごとに保存されます。
6プロセス番号の再利用
history.csvはPID210の生成と終了を記録した表です。開始時刻STARTをPIDと一緒に読みます。
cat生成と終了の記録 history.csvPID再利用の例09:00開始のworkerは09:02に終了し、10:00開始のbackupに同じPID210が割り当てられています。番号だけで二つの記録を結び付けると、別プロセスの動作を一つに混ぜてしまいます。
7開始時刻を含めて絞り込む
09:00に開始したプロセスの記録だけを取り出します。同じPIDの後のプロセスを条件で除きます。
awk -F,履歴の列を読む 'NR==1 || ($2==210 && $3=="09:00:00")'PIDと開始時刻の一致 history.csv履歴表startとexitの2記録が残ります。長期間の調査では起動IDやホスト名、時刻の精度も識別条件に含めます。この表では同じホスト・同じOS起動内に限定し、開始時刻を秒で固定しています。
まとめ
同じ名前のプログラムでも、PIDが異なれば別プロセスとして管理されます。
同一プロセスのスレッドはアドレス空間を共有し、スタックの置き場所や実行状態を個別に持ちます。
PIDは再利用されるため、履歴では開始時刻などの識別情報も使います。
操作履歴と解説を振り返れます。
シェル / プロセス
cat tasks.csvPID,TID,PPID,START,PROGRAM,VM,FD_TABLE,STATE 210,210,100,09:00:00,worker,A,F1,S 210,211,100,09:00:00,worker,A,F1,R 310,310,100,09:00:05,worker,B,F2,S
awk -F, 'NR>1 {print $1}' tasks.csv | sort -u | wc -l; awk -F, 'NR>1 {n++} END {print n}' tasks.csv2 3
awk -F, 'NR==1 || $2=="0x4000"' memory.csvVM,ADDRESS,VALUE,REGION A,0x4000,10,heap B,0x4000,90,heap
awk -F, 'BEGIN {OFS=FS} $1=="A" && $2=="0x4000" {$3=11} {print}' memory.csv > after.csv; cat after.csvVM,ADDRESS,VALUE,REGION A,0x4000,11,heap B,0x4000,90,heap A,0x8000,0,thread210_stack A,0x9000,0,thread211_stack
awk -F, 'NR==1 || $4 ~ /stack/' after.csvVM,ADDRESS,VALUE,REGION A,0x8000,0,thread210_stack A,0x9000,0,thread211_stack
cat history.csvTIME,PID,START,PROGRAM,EVENT 09:00:00,210,09:00:00,worker,start 09:02:00,210,09:00:00,worker,exit 10:00:00,210,10:00:00,backup,start
awk -F, 'NR==1 || ($2==210 && $3=="09:00:00")' history.csvTIME,PID,START,PROGRAM,EVENT 09:00:00,210,09:00:00,worker,start 09:02:00,210,09:00:00,worker,exit
演習完了