ミューテックス
複数のスレッドが共有リソースに同時アクセスすることを防ぐ排他制御の同期プリミティブ
並行処理非同期
ミューテックスとは
ミューテックス (Mutex: Mutual Exclusion) は、複数のスレッドが共有リソースへ同時にアクセスすることを防ぐ同期プリミティブである。1 つのスレッドがロックを取得している間、他のスレッドは解放されるまで待機する。
ミューテックス vs セマフォ
| 観点 | ミューテックス | セマフォ |
|---|---|---|
| 同時アクセス数 | 1 (排他) | N (カウンタ) |
| 所有権 | ロックした者だけが解放 | 誰でも解放可能 |
| 用途 | 共有リソースの保護 | リソースプールの制限 |
Rust の Mutex
use std::sync::{Arc, Mutex};
use std::thread;
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
handles.push(thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
})); // ロックはスコープを抜けると自動解放
}
for h in handles { h.join().unwrap(); }
assert_eq!(*counter.lock().unwrap(), 10);
Go の sync.Mutex
var mu sync.Mutex
var count int
mu.Lock()
count++
mu.Unlock()
デッドロック
スレッド A: Lock(X) → Lock(Y) を待つ
スレッド B: Lock(Y) → Lock(X) を待つ
→ 互いに相手の解放を待ち、永久に停止
| 対策 | 説明 |
|---|---|
| ロック順序の統一 | 常に X → Y の順でロック |
| タイムアウト | 一定時間で諦める |
| ロックの粒度を細かく | 必要最小限の範囲でロック |
Lambda とミューテックス
Lambda はリクエストごとに独立した実行環境で動作するため、プロセス内のミューテックスは不要。複数の Lambda 間の排他制御には分散ロック (DynamoDB の条件付き書き込み) を使う。
// Lambda: 分散ロック (ミューテックスの代替)
await db.put({
TableName: 'locks',
Item: { lockId: 'resource-1', owner: requestId, expiresAt: Date.now() + 30000 },
ConditionExpression: 'attribute_not_exists(lockId) OR expiresAt < :now',
ExpressionAttributeValues: { ':now': Date.now() },
});
ロックフリーアルゴリズム
| 方式 | 説明 |
|---|---|
| CAS (Compare-And-Swap) | CPU 命令でアトミックに更新 |
| Atomic 型 | ロックなしでカウンタを更新 |
| 不変データ | データを変更しない設計 |
ミューテックスを扱う関連書籍も多い。