並行性の観測。データレース、デッドロック、タイミング依存バグを検出。Use when: async/await実装、スレッド/goroutine使用、共有状態操作、本番でだけ起きる問題、たまに落ちるテスト調査。
This skill inherits all available tools. When active, it can use any tool Claude has access to.
並行性バグは「通常テストが通るのに本番で死ぬ」の代表。 このスキルは、非決定性を再現可能な失敗に変える。
| バグ種別 | 症状 | 検出方法 |
|---|---|---|
| データレース | 同時書き換え/読み書き競合 | レースデテクタ |
| デッドロック | ロック順、待ち合わせ | デッドロック検出 |
| ライブロック | 特定条件で進まない | タイムアウト監視 |
| await忘れ | 非同期順序の取り違え | 静的解析 |
| キャンセル漏れ | リソースリーク | ストレステスト |
並行アクセスされる共有可変状態を列挙:
[ ] グローバル変数
[ ] シングルトンの可変フィールド
[ ] キャッシュ(in-memory)
[ ] 接続プール
[ ] ファイルシステム
言語別の実行方法:
# Go
go test -race ./...
# Rust
cargo +nightly miri test
# C/C++
clang -fsanitize=thread -g program.c
# Python (ThreadSanitizer with C extensions)
# 直接サポートなし → ストレステストで補完
# Node.js
# 直接サポートなし → ストレステストで補完
"たまたま通る"を潰すための増幅器:
import concurrent.futures
import threading
def test_counter_under_stress():
counter = SharedCounter()
def increment_many():
for _ in range(1000):
counter.increment()
# 100スレッドで同時実行
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
futures = [executor.submit(increment_many) for _ in range(100)]
concurrent.futures.wait(futures)
# 期待値: 100 * 1000 = 100,000
assert counter.value == 100000
# キュー飽和の監視
def test_queue_does_not_saturate():
queue = TaskQueue(max_size=1000)
# 大量タスク投入
for i in range(10000):
queue.put(Task(i))
# 一定時間内に処理完了
start = time.time()
queue.join()
elapsed = time.time() - start
assert elapsed < 60 # 60秒以内に完了
assert queue.dropped_count == 0 # ドロップなし
# 並行性関連メトリクス
metrics:
- name: thread_pool_active_threads
type: gauge
labels: [pool_name]
- name: queue_depth
type: gauge
labels: [queue_name]
- name: request_timeout_total
type: counter
labels: [endpoint]
- name: lock_wait_seconds
type: histogram
labels: [lock_name]
並行性がある領域のみ適用:
並行性バグを予防する設計パターン:
| パターン | 説明 |
|---|---|
| スレッド閉じ込め | 特定スレッドのみがデータにアクセス |
| イミュータブル | 変更不可なデータ構造 |
| メッセージパッシング | チャネル/アクター経由の通信 |
| 読み書きロック | 読み取りは並行、書き込みは排他 |
# .github/workflows/race.yml
name: Race Detection
on: [push, pull_request]
jobs:
race:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Run tests with race detector
run: go test -race -v ./...
import { Worker } from 'worker_threads';
describe('Concurrency Stress', () => {
it('handles concurrent writes without data loss', async () => {
const writes: Promise<void>[] = [];
// 100並列で書き込み
for (let i = 0; i < 100; i++) {
writes.push(db.insert({ id: i, value: `data-${i}` }));
}
await Promise.all(writes);
// 全件書き込まれていること
const count = await db.count();
expect(count).toBe(100);
});
});