Dev Study
← コンピュータの仕組み
レッスン 12 / 13·約 13 分·第1期 コンピュータ単体の仕組み

OSの役割 — 1つのCPUを、みんなで分け合う

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力
  2. DNS名前→IP
  3. ルータ経路選択
  4. ロードバランサ振り分け
  5. Nginx受け口
  6. アプリ処理今ここ
  7. DB保存

ここまでCPU・メモリ・記憶装置という部品を見てきました。今回はそれらを束ねて、複数のアプリに分け与えている管理者、OSの役割を扱います。

まず結論

CPUのコア1つは、同時には1つの処理しか実行できません。何十個ものアプリが同時に動いて見えるのは、OSが高速に切り替えているからです。

切り替えには1〜数マイクロ秒かかりますが、本当の代償はそこではありません。切り替えるとキャッシュとTLBの中身が入れ替わり、その影響の方がはるかに大きくなります。

? 読む前に予測

4コアのCPUで、100個のプロセスが「同時に」動いているように見えます。実際には何が起きているでしょうか。

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

同時に動いているように見えるが、実際は順番待ち

いまPCでは何十個ものプログラムが動いています。ブラウザで動画を見ながら、エディタで文章を書き、裏でバックアップが走る。すべて同時に動いているように見えます。

ところがCPUのコア1つは、同時には1つの処理しか実行できません。4コアなら本当に同時に走れるのは4つだけです。では残りの何十個はどうなっているのでしょうか。

答えは順番待ちです。OSがごく短い時間で次々と切り替えているので、人間には同時に見えます。映画のコマ送りが連続した動きに見えるのと同じ原理で、切り替えが十分速ければ「止まっていた時間」に気づきません。

この切り替えを取り仕切るのがOSの中核的な仕事、スケジューリングです。

具体実物

切り替えのたびに、何が保存されるのか

タスクAからタスクBへ切り替えるとき、Aの状態を丸ごと保存しておかないと、後で再開できません。

コンテキストスイッチで起きること
タスクAを止めるレジスタとプログラムカウンタを退避○ 再開できる状態を保存
ページテーブルを切り替えるCR3レジスタを書き換え○ Bの仮想アドレス空間へ
タスクBを復元Bが前回退避した状態を戻す○ Bが続きから再開
ただし副作用が残るキャッシュとTLBにはAのデータが残っている× Bにとっては役に立たない
↓
切り替え処理自体は1〜数µs。しかし本当の代償は最後の行にある
  • ・第9週で学んだページテーブルの切り替えが、ここで効いてくる
  • ・キャッシュが温まり直すまで、しばらく遅い状態が続く

最後の行が重要です。 レジスタは退避・復元できますが、キャッシュとTLBの中身は持ち運べません。切り替えた直後のタスクBは、前回学んだ「キャッシュミス」を大量に起こしながら走ることになります。

✓ ここまでの確認

コンテキストスイッチのコストとして、最も影響が大きいのはどれですか。

抽象原理

プロセスとスレッドは、実は同じもの

「プロセスとスレッドの違い」はよく聞かれる質問ですが、Linuxでの答えは意外です。

どちらも同じ構造(task_struct)で管理されています。 違いは、作るときに何を共有すると指定したかだけです。

プロセスとスレッドの実際の違い表
プロセス スレッド
カーネル内の構造 task_struct task_struct(同じ)
アドレス空間 専用 共有する
スタック 専用 各自が持つ(共有しない)
スケジューラの扱い 区別しない 区別しない

つまり「プロセスとスレッドは別の仕組み」ではなく、同じ仕組みの設定違いです。アドレス空間を共有すればスレッドと呼ばれ、共有しなければプロセスと呼ばれます。

そしてスケジューラは、この違いを気にしません。**選ぶ単位はスレッド(タスク)**で、プロセスではありません。1つのプロセスが8本のスレッドを持っていれば、スケジューラから見れば8個の候補です。

具体実物

どのタスクを次に選ぶかの方式は、最近変わった

「次にどのタスクを走らせるか」を決める方式は、長らく CFS(Completely Fair Scheduler) でした。多くの教材や記事が今もそう書いています。

しかし現在は EEVDF に置き換わっています。

スケジューラの変遷(kernel.org・kernelnewbies より)表
Linux 6.6 (2023年10月) EEVDF を導入
Linux 6.12 (2024年11月) EEVDF への移行が完了
 
ただし現在も残っているもの:
ソースファイル名 kernel/sched/fair.c
ポリシー定数 SCHED_NORMAL
→ 「CFS」の名前はコード上に残存している

ここで注意すべきは、名前がコードに残っていることです。ソースを見れば fair.c とあり、冒頭のコメントには今も "Completely Fair Scheduling (CFS) Class" と書かれています。だから「CFSが現役だ」と書かれた記事が量産され続けます。

✓ ここまでの確認

「Linuxの標準スケジューラはCFSです」という説明を2026年に見ました。どう判断しますか。

この章のまとめ

  • コア1つは同時に1つの処理しか実行できない。同時に見えるのはOSが高速に切り替えているから。
  • 切り替え(コンテキストスイッチ)は1〜数µs。しかし本当の代償はキャッシュとTLBが入れ替わることで、作業データが大きいと2桁悪化しうる。
  • Linuxではプロセスもスレッドも同じ task_struct。違いは「何を共有するか」だけ。スケジューラは区別しない。
  • 選ぶ単位はプロセスではなくスレッド(タスク)。だから1プロセスのCPU使用率が100%を超えうる。
  • 通常タスクのスケジューラはCFSからEEVDFへ移行済み(6.6導入・6.12完了)。ただしコード上にCFSの名前が残るため、古い情報が生き延びやすい。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 4正解: 0

Linuxにおけるプロセスとスレッドの違いとして正しいものはどれですか。

用語集(5語)
プロセス
実行中のプログラム。自分専用のアドレス空間を持つ。Linuxでは task_struct で管理される。
スレッド
プロセス内の実行単位。アドレス空間を共有するが、スタックは各自が持つ。Linuxではプロセスと同じ task_struct で管理される。
スケジューラ
次にどのタスクをCPUで走らせるか決めるOSの部品。現在のLinuxの通常タスク向けはEEVDF。
コンテキストスイッチ
CPUで走らせるタスクを切り替えること。レジスタの退避・復元に加え、キャッシュとTLBが入れ替わる影響が大きい。
EEVDF
Earliest Eligible Virtual Deadline First。Linux 6.6で導入、6.12で移行完了した通常タスク向けスケジューラ。従来のCFSを置き換えた。