1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ctrl-Cでパイプ全体が止まるのはなぜか sessionとprocess groupとdaemonで整理する

1
Posted at

はじめに

cmd1 | cmd2 | cmd3 を実行しているときに Ctrl-C を押すと、なんとなく「まとめて kill された」ように見えます。

ただ、正確には少し違います。

  • Ctrl-C が送るのは SIGKILL ではなく SIGINT
  • 相手は親プロセス 1 個ではなく foreground process group
  • シェルはパイプでつないだコマンド群を同じ process group に入れる

この 3 点だけ押さえると、なぜパイプ全体が止まるのか、なぜ daemon 化した子には届かないのかが見通しやすくなります。

この記事のゴール

この記事では、次の疑問をまとめて整理します。

疑問 この記事で分かること
Ctrl-C は誰に届くのか foreground process group に SIGINT が届く
なぜパイプ全体が止まるのか シェルが同じ process group にまとめるから
daemon はなぜ残るのか session と端末から独立するから
まとめて止めたいときはどう見るか PID ではなく PGID を見ると整理しやすい

先に結論

  • Ctrl-C は端末の foreground process group に SIGINT を送る
  • パイプでつないだ一連のコマンドは、通常は同じ process group に属する
  • そのため cmd1 | cmd2 | cmd3Ctrl-C でまとめて止まりやすい
  • daemonsetsid などで元の端末から切り離されるので、元のシェルの Ctrl-C は届かない

まずは用語を 1 枚で整理する

用語 ざっくりした意味 Ctrl-C との関係
session 端末をぶら下げる大きな単位 controlling terminal と結びつく
process group ジョブ制御やシグナル配送の単位 foreground group が SIGINT を受ける
shell コマンドを起動し、group を組み立てる役 パイプ全体を同じ group に入れる
daemon 端末から独立して動く常駐プロセス 元の端末の Ctrl-C は届きにくい

関係を図にするとこうです。

図中の略称だけ補足します。

図中ラベル 意味
session session leaderlogin shell など
fg PG foreground process group
bg PG background process group

Ctrl-C は何をしているのか

よく「Ctrl-C でプロセスを kill する」と言いますが、実際に起きていることは次です。

操作 実際の動作
Ctrl-C 端末ドライバが foreground process group に SIGINT を送る
kill PID 指定した PID にシグナルを送る
kill -- -PGID 指定した process group 全体にシグナルを送る

つまり Ctrl-C は「今この端末の前面で動いている group に割り込みを送る」動作です。
親プロセスだけを狙っているわけではありません。

なぜパイプ全体が止まるのか

たとえば次を考えます。

sleep 100 | cat >/dev/null

シェルはこの 2 つを起動するとき、通常は同じ process group に入れます。
そのため Ctrl-C が飛ぶ先は個々の PID ではなく、その PGID 全体です。

流れを図にするとこうです。

図では shell を別に置いていますが、Ctrl-C の配送先は shell ではなく fg PG です。

ps で見ると確かに同じ group になる

バックグラウンドで起動して jobsps を見ると、同じ PGID になっていることが確認できます。

sleep 100 | cat >/dev/null &
jobs -l
ps -o pid,ppid,pgid,sid,tty,stat,comm --forest -g <PGID>

イメージは次のような出力です。

PID PPID PGID SID COMMAND
1001 999 1001 1001 sleep
1002 999 1001 1001 cat

ここで重要なのは PID が別でも PGID が同じ、という点です。
Ctrl-C で効いているのはこの PGID 側です。

session はどこで効いてくるのか

process group の外側には session があります。
session は controlling terminal と結びつく単位で、foreground process group はその中で前面実行されている group です。

判定の流れを表にするとこうです。

レイヤ 役割
terminal 入力元 今開いている端末
session その端末に属するまとまり ログインシェルの世界
process group 前面実行や停止制御の単位 パイプ全体のジョブ
process 実際の個々の実行単位 sleep proc, cat proc など

このため Ctrl-C を理解するときは、PID だけでなく terminal -> session -> process group -> process の順で見ると混乱しにくいです。

daemon が止まらない理由

daemon は端末から独立した常駐プロセスです。
多くの場合、次のような手順で元の端末から切り離されます。

手法 何をするか 効果
nohup SIGHUP を無視する 端末クローズ耐性を上げる
setsid 新しい sessionprocess group を作る 元の端末から切り離す
daemon 化 forksetsid、標準入出力切り離し 常駐プロセス化する

特に重要なのは setsid です。
これで新しい session に入ると、元の端末の foreground process group とは別世界になります。

ここでは child procsetsid() を呼ぶことで new session 側へ移り、元の terminal からの SIGINTold fg PG にだけ届きます。new session 側にはその配送経路がありません。

nohup だけでは別の話

混ざりやすいので、nohup も並べておきます。

コマンド 主に防ぐもの Ctrl-C への効き方
nohup cmd 端末切断時の SIGHUP Ctrl-C から完全独立するとは限らない
setsid cmd 端末との結びつき 元の端末の Ctrl-C が届きにくくなる

nohup は「端末を閉じたとき対策」であって、Ctrl-C 対策そのものではありません。

まとめて止めたいときの実務メモ

関連する一式を止めたいときは、PID ではなく PGID を見ると整理しやすいです。

kill -INT -- -<PGID>   # Ctrl-C 相当
kill -- -<PGID>        # 既定は SIGTERM
kill -KILL -- -<PGID>  # 最終手段

Bash のジョブ制御を使っているなら、ジョブ番号で扱うのも手軽です。

sleep 100 | cat >/dev/null &
kill %1

使い分けを表にするとこうです。

止め方 向いている場面
kill PID 単独プロセスを止めたい
kill -- -PGID パイプや関連ジョブをまとめて止めたい
kill %1 今のシェルのジョブとして止めたい

まとめ

  • Ctrl-C が送るのは SIGKILL ではなく SIGINT
  • 宛先は親プロセスではなく foreground process group
  • パイプ全体が止まるのは、シェルが同じ process group にまとめるから
  • daemon が残るのは、session ごと端末から独立するから
  • まとめて制御したいときは PID より PGID を意識すると整理しやすい

Linux のプロセス管理は PID だけを見ていると分かりにくいですが、sessionprocess group を一段上の単位として見ると、Ctrl-C の挙動がかなり素直に見えるようになります。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?