0
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?

#0253(2025/10/04)Ctrl-Cはなぜプログラムを終了できるのか

Posted at

Ctrl-Cはなぜプログラムを終了できるのか

Ctrl-Cとは、端末のラインディシプリンが前景プロセス群へSIGINTを配送させる仕組みである。

中級者がつまずきがちなポイントは、Ctrl-Cが「CPUを止める魔法のキー」ではなく「シグナル配送を起動するきっかけ」にすぎないこと。ここでは、TTYとプロセスグループ、シグナル、そして例外的に止まらないケースまで、実務で役立つ粒度で解説する。

仕組みの全体像

端末へCtrl-Cを送ると、端末ドライバが割り込み文字を検知し、カーネルが前景プロセスグループにSIGINTを送る。多段パイプラインでも同じプロセスグループに所属していれば全員へ飛ぶ。アプリがRAWモードにしていれば、ラインディシプリンは介在せずアプリが0x03をただのバイトとして受け取る。

キーワード早見:

  • ラインディシプリン 端末入力の編集や制御を司る層。stty intr で割り込み文字を変更できる。
  • 前景プロセスグループ 同じジョブに属するプロセスの集合。シェルが制御する。
  • SIGINT デフォルトは終了。アプリが捕捉すれば挙動は変えられる。

Ctrl-Cは何を止めているのか

本質は「プロセスのメインスレッドへ非同期イベントを通知している」こと。POSIXではSIGINTのデフォルト動作は終了だが、言い換えると終了するかどうかは最終的に各プロセス次第だ。

  • どこへ届くか 端末の前景プロセスグループ全体。パイプ a | b | c なら a b c の全プロセスへSIGINT。
  • システムコール中なら 多くのブロッキング呼び出しはEINTRで中断され、アプリが戻り値を見て処理を打ち切る。
  • ただしSA_RESTARTありなら 同じシステムコールが自動再開され、ユーザ視点では効いていないように見えることがある。

似て非なるシグナルやキーとの比較

入力や操作 送られるシグナル デフォルト動作 典型的用途 備考
Ctrl-C SIGINT 終了 実行の中断と終了 前景プロセスグループ全体へ配送
Ctrl-Z SIGTSTP 停止 一時停止してシェルへ戻る bg fg で再開可能
Ctrl backslash SIGQUIT コアダンプ付き終了 デバッグ用強制終了 多くの端末でquitに割り当て
端末を閉じる SIGHUP 終了 端末切断の通知 nohupで無視させる運用あり
kill TERM pid SIGTERM 終了 丁寧な終了 デフォルトの終了要求
kill KILL pid SIGKILL 強制終了 最終手段 捕捉不可 無視不可

Ctrl-Cで止まらないものは何か

現場で遭遇しがちなパターンを、原因と対処の観点でまとめる。

ケース 止まらない理由の本質 典型例 実務での対処
RAWモードのフルスクリーンアプリ ラインディシプリンをバイパスしており、0x03はただの入力 エディタやTUI アプリ側のショートカットやコマンドで抜ける 設定次第でSIGINTをハンドル
プロセスがSIGINTを無視または捕捉 signalで無視や独自処理している サーバやREPL kill TERM や設定変更 終了パスを実装
シグナルをマスク中 一時的に配達が保留される クリティカルセクション マスク解除を待つ 設計見直し
システムコールが自動再開 SA_RESTARTで再開されユーザが効き目を感じにくい ネットワークI O ループでEINTRを扱い中断パスを用意
カーネルのD状態でブロック アンインタラプタブルスリープで割り込み不可 NFSやデバイス待ち 原因I Oの復旧のみ有効 再起動検討
バックグラウンドジョブ 前景グループでないため受け取らない コマンド末尾にampersand fgしてからCtrl-C もしくはkill
制御端末を持たないデーモン 端末由来のシグナル経路が存在しない サービスプロセス systemctlやkillで管理
別のプロセスグループに分離 setsidで独立 nohup setsid pgidやセッションを確認してkill

パイプラインではどう見えるか

次のようなパイプラインを考える。

  • yes | head

Ctrl-Cは両者に飛ぶが、しばしばheadが先に終了してパイプを閉じ、yesにはSIGPIPEが飛んで自然終了する。パイプライン全体が落ちるため、ユーザの体感としてはCtrl-Cで全部止まったように見える。

実務で役立つ観点

  • 端末側の設定確認

    • stty a で intr erase susp などの割り当てを確認
    • intrを変えたいなら stty intr ^]
  • シグナルの扱い

    • プログラムではSIGINTを捕捉して安全に終了するパスを必ず用意する
    • ブロッキングI Oを使うならEINTRとSA_RESTARTの挙動を設計に織り込む
  • 現場調査の指針

    • ps o pid,ppid,pgid,stat,tty,cmd でプロセスグループと状態を可視化
    • proc pid statusやwchanでブロック点を探る D状態ならI Oの復旧が先
    • どうしても抜けないならSIGTERM SIGQUIT それでもダメならSIGKILLへ段階的に

Windowsコンソールとの違い

観点 Unix系 Windowsコンソール
生成されるイベント SIGINT CTRL_C_EVENT
配送対象 前景プロセスグループ コンソールのプロセスグループ
既定動作 終了 既定は終了だがハンドラで抑止可能
APIの扱い sigaction など SetConsoleCtrlHandler
RAWモード相当 端末をrawへ コンソールモードの設定で近似

実務ではWSLを含め、同じキーでも実装差があることを念頭に置く。

よくある誤解の撲滅メモ

  • Ctrl-Cは常に即座に止まるわけではない 再開可能なシステムコールやD状態がある
  • Ctrl-Cは特定スレッドだけを止めるものではない プロセスへシグナルが届き、スレッドへの配送はOSとランタイムの領域
  • Ctrl-Cが届かないのは端末やジョブ制御の設計次第 制御端末が無ければ届かない

まとめ

Ctrl-Cは、端末ドライバが検知した割り込み文字を合図に、カーネルが前景プロセスグループへSIGINTを配送する仕組みでプログラムを終わらせる。止まらないときは、RAWモード 無視やマスク D状態 ジョブ制御の境界など、伝播経路のどこが詰まっているかを見極めれば、正しい手段を選べる。設計では、安全な終了パスとEINTR対応を最初から組み込み、運用ではシグナルを段階的に使い分けるのが堅牢さへの近道だ。

0
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
0
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?