コース一覧
OS入門:プロセス・メモリ・ファイルシステム
レースコンディション

OS入門:プロセス・メモリ・ファイルシステム

OSがCPU・メモリ・ストレージをどのように管理しているかを、プロセス、スレッド、仮想メモリ、ファイルシステム、同期と並行性から体系的に学びます。アプリケーションの裏側で何が起きているかを説明できるようになります。

1
OS とは
0. コンピューターとOSの役割15分
1. OSの歴史(バッチ→マルチタスク→マルチユーザー)15分
2. カーネルとユーザーランド15分
3. システムコールの仕組み15分
4. Linux / macOS / Windows のアーキ比較15分
2
プロセスとスレッド
0. プロセスとは15分
1. スレッドとプロセスの違い15分
2. コンテキストスイッチ15分
3. スケジューラとアルゴリズム15分
4. プロセス間通信(IPC)15分
3
メモリ管理
0. メモリ階層(レジスタ→キャッシュ→RAM→ディスク)15分
1. 仮想メモリ15分
2. ページングとスワップ15分
3. mmap とメモリマップトファイル15分
4. ガベージコレクション概要15分
4
ファイルシステム
0. ファイルシステムとは15分
1. i-node とディレクトリ15分
2. ext4 / APFS / NTFS の違い15分
3. ジャーナリングと耐障害性15分
4. パーミッションと所有者15分
5
同期と並行性
0. レースコンディション15分
1. Mutex と Semaphore15分
2. デッドロック15分
3. 非同期と並行15分
4. イベントループと epoll15分

OS入門:プロセス・メモリ・ファイルシステム

01コンピューターとOSの役割
02OSの歴史(バッチ→マルチタスク→マルチユーザー)
03カーネルとユーザーランド
04システムコールの仕組み
05Linux / macOS / Windows のアーキ比較
06プロセスとは
07スレッドとプロセスの違い
08コンテキストスイッチ
09スケジューラとアルゴリズム
10プロセス間通信(IPC)
11メモリ階層(レジスタ→キャッシュ→RAM→ディスク)
12仮想メモリ
13ページングとスワップ
14mmap とメモリマップトファイル
15ガベージコレクション概要
16ファイルシステムとは
17i-node とディレクトリ
18ext4 / APFS / NTFS の違い
19ジャーナリングと耐障害性
20パーミッションと所有者
21レースコンディション
22Mutex と Semaphore
23デッドロック
24非同期と並行
25イベントループと epoll

OS入門:プロセス・メモリ・ファイルシステム

レースコンディション

残高 10,000 円から 2 人が 3,000 円ずつ引いて、残高が 7,000 円になる

口座から引き落とす処理を考えます。やることは 3 つで、残高を読み、引き算し、書き戻します。1 件ずつ順に処理する限り、何も問題は起きません。

問題は、同じ口座への 2 件のリクエストが、別々のスレッドで同時に走ったときです。

プレーンテキスト

時刻   スレッド A               スレッド B               残高
 1     残高を読む → 10000                                10000
 2                              残高を読む → 10000       10000
 3     10000 - 3000 = 7000                               10000
 4                              10000 - 3000 = 7000      10000
 5     7000 を書き戻す                                    7000
 6                              7000 を書き戻す           7000

合計 6,000 円引いたのに、減ったのは 3,000 円です。例外は飛びません。ログを見ても、2 件とも正常に完了しています。こういう壊れ方を レースコンディション と呼びます。

1 行のコードが、途中で止まる

「読んで、引いて、書き戻す」を 1 行で書けば安全に見えます。

Python

balance -= 3000

しかし CPU が実行するのは 1 命令ではありません。RAM から値をレジスタへ読み、レジスタで引き算し、レジスタの値を RAM へ書き戻す、という 3 段階です。OS はこの 3 段階のどこででもスレッドを止め、別のスレッドに CPU を渡せます。上の表と同じことが、たった 1 行の中で起きます。

厄介なのは、止まる場所が毎回違うことです。1 万回に 1 回しか壊れず、手元では再現せず、負荷が上がった本番でだけ数字が合わなくなります。

途中を見せてはいけない区間がある

問題の本質は、分割されると困る区間があるのに、そこが分割されてしまうことです。読んでから書き戻すまでの間、残高は「古い値のまま」という嘘をついています。この嘘を他人に見せてはいけません。このような区間を クリティカルセクション と呼びます。

やるべきことは 1 つです。この区間には、同時に 1 つのスレッドしか入れないようにする。これを相互排除と言います。

手軽な逃げ道と、その限界

整数を 1 つ増やす程度の単純な操作なら、CPU に「読み・変更・書き戻しを分割不可能に実行する」専用命令があります。Java の AtomicInteger、Go の sync/atomic、Rust の AtomicI64 はこれを使っています。

Go

var counter int64
atomic.AddInt64(&counter, 1)   // 途中で止まらない

速くて確実ですが、守れるのは 1 つの数値だけです。冒頭の引き落としのように「残高を確かめ、減らし、履歴を 1 行足す」といった複数の操作をひとまとまりで守ることはできません。そこで必要になるのが、区間そのものに鍵をかける道具です。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • 処理計算や代入を表す長方形
  • リクエストWeb 通信の基本単位、ブラウザの問い合わせとサーバーの返答
  • スレッド1 つの質問に紐づく返信の集まり
生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/05/27·更新 2026/08/26

関連レッスン

  • Mutex と Semaphore

    同時に一つしか入れない Mutex と、N 個まで入れる Semaphore の違いを、所有権の概念と具体的な使いどころを示しながら分かりやすく整理します。

  • デッドロック

    複数スレッドが互いのロックを待ち合って永久停止するデッドロックの成立条件と、ロック順序の固定やタイムアウトなど複数の防止策を実務目線で解説します。

  • 非同期と並行

    並行と並列の違い、I/O 待ちの間に他の仕事を進める非同期処理の考え方を、コールバックから async/await への進化とあわせて初学者にも分かる形で解説します。

  • イベントループと epoll

    I/O 完了イベントを一スレッドで順次処理するイベントループと、その基盤となる epoll や kqueue を使って大量同時接続をさばく仕組みを解説します。

分からないところは Tap (AI先生) に質問できます

24 時間いつでも、あなたのレベルに合わせて日本語で答えます。