TL

割り込みと入出力(I/O)

デバイスの「準備できたよ」をCPUに知らせる仕組みが割り込み。CPUは無駄に待たず、必要なときだけ反応してI/Oを効率よくさばく。

中級割り込みI/ODMAデバイスドライバ最終更新: 2026-06-04
TL;DR要点だけ先に
  • 1.割り込み(interrupt)は、デバイスからCPUへの「処理が終わった/要求がある」という非同期の通知。
  • 2.ずっと聞き続けるポーリングより、割り込みのほうがCPUを無駄なく使える(ただし用途次第)。
  • 3.高速転送はDMAがCPUを介さずメモリへ直送し、デバイスドライバが差を吸収。アプリ側はブロッキング/ノンブロッキングで待ち方を選ぶ。

なぜ割り込みが要るのか

CPU はナノ秒単位で動きますが、ディスクやネットワーク、人間のキー入力は 桁違いに遅い です。データが届くのを CPU が待ち続けたら、その間は何もできず大損です。

そこで「用意ができたら向こうから知らせてもらう」方式にします。これが割り込みです。CPU は待っている間、別のプロセスを動かせます(この「待ちのあいだ別の仕事をする」発想は /os/scheduling//os/process-thread/ とも深く関わります)。

ポーリング vs 割り込み

デバイスの状態を知る方法は大きく2つあります。

  • ポーリング(polling):CPU が「もう終わった?」と定期的に 自分から確認 しに行く
  • 割り込み(interrupt):デバイスが終わったら 向こうから通知 してくる
観点ポーリング割り込み
きっかけCPUが自分で繰り返し確認デバイスがCPUに通知
CPU使用待っている間も消費(空回り)通知が来るまで他の仕事ができる
遅延(応答)次の確認まで待つことがある発生時にほぼ即応
実装単純(ループで状態を読む)ハンドラ・割り込みベクタが必要
向く場面超高速・高頻度なデバイス低頻度・予測できないイベント
どちらが優れている、ではない

「割り込みのほうが上位互換」ではありません。NIC のように 毎秒大量のパケット が来ると、1件ごとの割り込みで処理が割り込み嵐(interrupt storm)になり逆に遅くなります。そこで高速ネットワークでは、しばらく 割り込みを止めてポーリングに切り替える(Linux の NAPI など)混在方式が使われます。

I/O が完了するまでの流れ

割り込みを使った典型的な入出力は、ざっくりこう進みます。

1. アプリが read() などでカーネルにI/Oを依頼(システムコール)
2. デバイスドライバがデバイスへ「読んで」と指示
3. CPUは待たず、別のプロセスを実行(依頼元プロセスはブロック)
4. デバイスがデータを用意 → CPUへ「割り込み」発生
5. CPUは実行中の処理を中断し、割り込みハンドラへジャンプ
6. ハンドラがデータを回収し、待っていたプロセスを「実行可能」に戻す
7. 中断した処理に復帰

ステップ5で CPU は、いま使っているレジスタなどの状態を退避し、割り込みベクタテーブル を引いて対応する 割り込みハンドラ(ISR: Interrupt Service Routine) に飛びます。ここでの「状態を退避して別処理に移り、後で戻る」感覚は /os/system-call/ の制御移行とよく似ています。

割り込みハンドラは「短く」が鉄則

ISR の実行中は他の割り込みが待たされやすいため、ハンドラ内で重い処理をしてはいけません。実務では「最低限だけハンドラで行い(前半/top half)、残りの重い処理は後回しにする(後半/bottom half・Linux の softirq/tasklet/threaded IRQ)」という二段構えが定石です。

DMA:CPUを介さずメモリへ直送

データ1バイトごとに CPU がコピーしていては、せっかく割り込みにしても CPU が忙しすぎます。そこで DMA(Direct Memory Access) を使います。

  • DMA コントローラ がデバイスとメモリの間を CPU を経由せずに 転送する
  • CPU は「ここからここへ転送して」と最初に指示するだけ
  • 転送が 全部終わったとき にだけ、DMA が CPU へ 完了割り込み を上げる
[割り込み駆動コピー]  デバイス → CPU → メモリ   (バイトごとにCPUが介在)
[DMA転送]            デバイス → メモリ          (CPUは開始と完了通知だけ)

つまり DMA は「転送中の CPU 解放」、割り込みは「完了の通知」を担当し、両者は 組み合わせて 使われます。大きなディスク読み込みやネットワーク受信が CPU を食いつぶさないのは DMA のおかげです。

デバイスドライバ:差を吸収する層

世の中のデバイスは型番ごとにレジスタも作法もバラバラです。それを デバイスドライバ が吸収し、OS には統一された使い方(read/write など)を見せます。

  • 上から見ると:OS の共通インターフェース(「ファイルのように」読み書き)
  • 下を見ると:その機器固有のレジスタ操作・割り込み処理

割り込みが来たとき実際に動く ISR も、多くはドライバの一部です。ドライバのおかげで、アプリは相手が SSD でも USB メモリでも 同じコード で扱えます。

ブロッキング vs ノンブロッキング I/O

ここまではカーネル内の話。アプリから見た「待ち方」 も2通りあります。

  • ブロッキング I/Oread() を呼ぶと、データが揃うまで その場で停止(プロセス/スレッドは眠る)
  • ノンブロッキング I/O:データがまだなら すぐ「まだ無い」と返る。後で再確認したり、まとめて多数の接続を監視(select/epoll/kqueue 等)する
観点ブロッキングノンブロッキング
呼び出し揃うまで返らない(待つ)未完了でも即返る
書きやすさ直線的で簡単状態管理やループが必要
多数の接続1接続=1スレッドで重くなりがち1スレッドで多数を多重化しやすい
相性順序処理・素朴なツール高並行サーバ・イベント駆動
「割り込み」と「ブロッキング」は別レイヤ

割り込みは ハードウェア↔カーネル の通知の仕組み、ブロッキング/ノンブロッキングは アプリ↔カーネル のAPIの振る舞いです。混同しがちですが層が違います。なお「待っている間ほかを進める」というノンブロッキングの考え方は、言語レベルの /programming/sync-async/ と地続きです。

まとめ

  • 割り込み:遅いデバイスからの非同期通知。CPU を見張りから解放する
  • ポーリングとの使い分け:低頻度なら割り込み、超高頻度なら(部分的に)ポーリング
  • DMA:転送そのものを CPU から肩代わりし、完了時だけ割り込む
  • ドライバ:機器ごとの差を隠し、統一インターフェースを提供
  • ブロッキング/ノンブロッキング:アプリ側の「待ち方」。割り込みとは別レイヤ

OS Article

割り込みと入出力(I/O)を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

割り込み

比較で見る軸

難易度: intermediate / カテゴリ: OS / タグ数: 4

導入後に効く点

ずっと聞き続けるポーリングより、割り込みのほうがCPUを無駄なく使える(ただし用途次第)。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
intermediate
カテゴリ
OS
タグ数
4

判断チェックリスト

  • 自社の用途が「割り込み / I/O」に近いか確認する。
  • 強みである「割り込み(interrupt)は、デバイスからCPUへの「処理が終わった/要求がある」という非同期の通知。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

割り込みI/ODMAデバイスドライバ割り込みI/ODMAデバイスドライバ
参考: 公式情報