【きょうごうじょうたい】

競合状態(レースコンディション) とは?

💡 「早い者勝ち」で結果が変わるバグ
📌 このページのポイント
競合状態(Race Condition) 変数 count = 0 (共有) スレッドA 1. 読取: count=0 2. 計算: 0+1=1 3. 書込: count=1 スレッドB 1. 読取: count=0 2. 計算: 0+1=1 3. 書込: count=1 同時にアクセス! 期待する結果 count = 2 実際の結果 count = 1 問題の流れ 両スレッドが古い値(0)を読み取り それぞれ+1して書き込むため 1回分の加算が消失する
複数スレッドの同時アクセスにより結果が不正になる問題
ひよこ ひよこ

具体的にどういう問題が起きるの?

ペンギン先生 ペンギン先生

カウンターを+1する操作を考えよう。①現在値を読む(100)→②+1する(101)→③書き戻す(101)。2つのスレッドが同時にやると、両方が①で100を読む→両方が101を書き戻す→結果は101(102であるべき)。1回分の加算が消失する「ロストアップデート」問題だよ

ひよこ ひよこ

Webアプリでも起きるの?

ペンギン先生 ペンギン先生

起きるよ。在庫が1個の商品を2人が同時に「カートに入れる」→両方が在庫チェックOK→両方が購入完了→在庫-1になるべきが-2に。ECサイトの二重販売はまさにレースコンディション。対策は楽観的ロック(バージョンチェック付きUPDATE)やSELECT FOR UPDATEによる行ロックだよ

ひよこ ひよこ

どうやって防ぐの?

ペンギン先生 ペンギン先生

ミューテックス/ロック:同時に1つのスレッドだけがアクセスできるようにする、②アトミック操作:読み取り→更新→書き込みを不可分な1操作にする、③楽観的ロック:更新時にバージョン番号をチェックして競合を検出、④不変(immutable)なデータ構造を使う。関数型プログラミングの「副作用を避ける」思想は競合状態の予防にもなるよ

ひよこ ひよこ

レースコンディションのデバッグのコツは?

ペンギン先生 ペンギン先生

再現が難しいのが最大の課題。①ThreadSanitizer(Go、C++)や-Xcheck:jni(Java)で検出、②ストレステストで同時アクセスを大量に発生させる、③ログにタイムスタンプとスレッドIDを出力して時系列を追う。「テスト環境では再現しないのに本番で起きる」ことが多いから、設計段階で競合を防ぐのが最も重要だよ

ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「競合状態」って出てきたら「同時アクセスで実行順序により結果が変わるバグ」と思えればだいたいOK!
📖 おまけ:英語の意味
「Race Condition」 = 競合状態
💬 Race(競争)。どのスレッドが先にゴールするかで結果が変わる「競争」だよ
← 用語集にもどる