実行中の処理を中断して別の処理を優先実行し、後で元に戻す仕組み
割込み(interrupt)とは、CPU(=コンピュータの頭脳)が今やっている処理をいったん中断し、急ぎの別の処理を優先的に実行してから、また元の処理に戻る仕組みのことです。
身近な例で考えると、料理中に電話が鳴ったときと同じです。包丁を置き(中断)、火を弱めて状態を覚えておき(退避)、電話に出て(割込み処理)、終わったら火加減を元に戻して(復元)料理を再開します。割込みがあっても、料理の続きをきちんと再開できるのがポイントです。
上のツールで ▶ ボタンを押すと、メインプログラム → 割込み発生 → 状態の退避 → 割込みハンドラ実行 → 状態の復元 → メインに復帰、という一連の流れを順番に確認できます。
割込みは、原因がどこにあるかで大きく2種類に分けられます。CPUの内側(実行中のプログラム)が原因なら内部割込み、CPUの外側(周辺装置など)が原因なら外部割込みです。
覚え方のコツは「原因がプログラム自身なら内部、ハードウェアなら外部」です。
・内部割込み:プログラムの異常(ゼロ除算・不正命令)やページフォルト、システムコールなど。例外とも呼ばれます
・外部割込み:入出力完了、タイマ、キーボード入力、ハードウェア異常など、CPUの外からやってくる通知
具体的には、ゼロ除算やページフォルトは内部、入出力完了やタイマは外部と区別できます。上のツールではシナリオを切り替えて、外部割込み(入出力完了)と内部割込み(ゼロ除算)の両方を見比べられます。
割込みの最大のポイントは、処理が終わったあとに元の続きへ正確に戻れることです。そのために、中断する瞬間に現在の状態を保存しておきます。
復帰までの流れ:
・退避(save):プログラムカウンタ(=次に実行する命令の番地)やレジスタの中身をスタック(一時的にデータを積む記憶領域)に保存する
・割込みハンドラの実行:割込みの種類に対応した専用プログラムを実行する
・復元(restore):スタックから状態を読み戻し、中断前と同じ状態にする
・復帰:保存しておいたプログラムカウンタの位置から、メインプログラムを再開する
この「しおりを挟んでおく」仕組みのおかげで、メインプログラムは割込みがあったことに気づかず、何事もなかったかのように続きを実行できます。割込み発生時にプログラムカウンタなどを退避するという流れがポイントです。上のツールの下段で、スタックへの退避・復元の様子を確認してください。
結論:割込みがないと、CPUが長い待ち時間の間ずっと何もできなくなってしまうからです。
コンピュータでは、CPUの計算速度と比べて、ディスクの読み書きやキーボード入力の完了を待つ時間は非常に長いです。I/O(=入出力操作のこと。Input/Outputの略)の完了を待つ間、もしCPUが何もせずポーリング(=「終わった?まだ?」と繰り返し確認すること)し続けると、他の計算が一切できず非効率です。
割込みを使うと、CPUはI/O完了を待つ間も別の処理を進め続けられます。I/Oが終わった瞬間にハードウェアが割込み信号を送り、CPUはそのタイミングで結果を受け取ります。これにより、CPUを休ませることなく複数の仕事を効率よく並行して進めることができるのです。上の図の上段と下段を見比べると、待ち時間の使い方の差が分かります。
まとめると、割込みには主に2つの役割があります。
・効率化:I/O待ちの間にCPUを別の処理に使える
・即時対応:キーボード入力やエラーなど、いつ起きるか分からない出来事に素早く反応できる
割込みには優先度(どの割込みを先に処理するか)という概念があります。複数の割込みが同時に発生したとき、CPUは優先度の高いものから処理します。
たとえば、電源異常は最優先で対処しなければならないため優先度が高く設定されています。一方、タイマ割込み(=一定時間ごとに発生する定期的な割込み)やキーボード入力などは比較的優先度が低いです。
また、すべての割込みを常に受け付けるわけではありません。状態の退避・復元を行っている最中など、割込みが来ると困るタイミングでは、CPUは一時的に割込みを無視する割込み禁止の状態になります。これは、途中で別の割込みが割り込んでデータが壊れるのを防ぐためです。
身近な例で考えると、救急車のサイレン(高優先度)はどんな状況でも優先されるが、電話中(割込み禁止中)はドアベルに出られないのと似ています。割込みには「受け付けていいタイミングかどうか」の管理も含まれるのです。