Claude Code に C/C++/Rust/Zig で同じ課題を実装させたら、言語ごとのふるまいに差は出るのか
話題の記事

Claude Code に C/C++/Rust/Zig で同じ課題を実装させたら、言語ごとのふるまいに差は出るのか

Claude Code (Opus 4.6) に LRU キャッシュと Thread Pool を C, C++, Rust, Zig で実装させ、生成品質・修理過程・コード理解度を比較しました。
2026.03.02

はじめに

AI にコードを書かせるとき、プログラミング言語の選択は生成品質に影響するのでしょうか。Rust のボローチェッカは AI の修理を助けるのか、C の単純さは AI に有利に働くのか……。Claude Code (Opus 4.6) に同一の課題を C, C++, Rust, Zig の 4 言語で実装させ、言語ごとの差異を観察してみました。

Rust とは

Rust は Mozilla で開発が始まったシステムプログラミング言語です。現在は Rust Foundation のもとコミュニティ主導で開発されています。所有権システムとボローチェッカにより、メモリ安全性とスレッド安全性をコンパイル時に保証します。

Zig とは

Zig は C の代替を目指すシステムプログラミング言語です。手動メモリ管理を採用しつつ、コンパイル時の計算 (comptime) やランタイム安全性チェックで安全性を補強しています。

対象読者

  • AI コード生成に関心のあるソフトウェアエンジニア
  • プログラミング言語の安全性機構に関心のある開発者
  • Claude Code の実用性を知りたい方

検証環境

  • OS: Windows 11 Home (Build 26200)
  • CPU: Intel Core i7-11700F, RAM: 32 GB
  • C/C++: MSVC v143 (Visual Studio 2022), CMake 4.2.1, C は Win32 API (CreateThread) でスレッド実装
  • Rust: rustc 1.93.1
  • Zig: 0.15.2
  • AI: Claude Code (Opus 4.6)

参考

検証の計画

言語の安全性機構が AI に影響を与えるとすれば、メモリ管理と並行処理が最も差が出やすい領域でしょう。C/C++ では手動管理が求められ、Rust ではコンパイラが厳格に検査し、Zig はランタイムチェックで補強するという、言語ごとのアプローチが最も分かれる領域だからです。

仮説としては、以下のいずれも起こり得ると考えました。

  1. Rust のボローチェッカが修理を助け、修正ラウンドが最少になる
  2. 逆にボローチェッカが AI を苦しめ、コンパイルエラーとの対話にラウンドを消費する
  3. C の単純さが AI に有利に働き、手動メモリ管理でも一発合格する
  4. 言語による差はほとんどなく、生成品質は言語に依存しない

検証方法

今回の検証では 2 つの課題を用意しました。

  • 課題 A: LRU キャッシュ
    メモリ管理が焦点で、所有権・寿命・解放責務が問われる。
  • 課題 B: Thread Pool
    並行処理が焦点で、shutdown・join・条件変数の同期が問われる。

各課題に対し、L1 テスト (仕様テスト 12 項目) と L2 ストレステスト (seed 固定、反復実行) を定義しました。AI が生成したコードがこれらのテストに合格するまで最大 5 ラウンドの修理を許可します。

交絡変数の制御

言語間で学習効果が持ち越されないよう、各言語の実装はそれぞれ独立した Claude Code セッションで行いました。各セッションに提供する情報は仕様書、テストコード、ビルドコマンドの 3 点のみです。

experiment-gif

また、完成コードに対する理解度テストも実施しました。AI が生成したコードの可読性が言語によって異なるのであれば、後から別の AI がそのコードを保守する際にも差が出るはずです。これを確かめるため、別のセッションに仕様書を渡さずコードだけを読ませ、概要説明、問題点の指摘、機能追加の 3 タスクを課しました。

結果 1: メモリ管理課題では差が出なかった

LRU キャッシュの結果です。

指標 C C++ Rust Zig
First-pass result 全通過 全通過 全通過 全通過
Rounds to green 0 0 0 0
Compile-fix cycles 0 0 0 0
Stress survival 全通過 全通過 全通過 全通過

4 言語とも初回で L1 テスト 12/12 に合格し、ストレステスト (10,000 反復) も通過しました。修理ラウンドは 0 回です。アルゴリズムの選択も 4 言語で共通しており、いずれもハッシュマップ + 双方向リンクリストという LRU キャッシュの定番パターンを採用しました。ただし Rust だけは、ボローチェッカとの折り合いのために独自の適応を見せています。

Rust のインデックスベースリスト

C の実装ではポインタでノードを連結します。

typedef struct Entry {
    int32_t key;
    uint8_t *value;
    size_t value_len;
    struct Entry *prev;
    struct Entry *next;
    struct Entry *hash_next;
} Entry;

一方 Rust の実装では、ポインタの代わりに Vec のインデックスでノードを連結します。

struct Node {
    key: i32,
    value: Vec<u8>,
    prev: usize,  // ポインタではなくインデックス
    next: usize,
}

pub struct LRUCache {
    capacity: usize,
    map: HashMap<i32, usize>,
    nodes: Vec<Node>,  // ノードの arena
    head: usize,       // センチネル (index 0)
    tail: usize,       // センチネル (index 1)
}

Rust で双方向リンクリストをポインタベースで実装すると、ノードが前後のノード両方から可変借用される形になり、unsafe なしでは成立しません。AI はこれを回避するために Vec<Node> を arena として使い、インデックスを疑似ポインタとして機能させる戦略を取りました。unsafe ブロックは 0 です。これは Rust コミュニティで知られたパターン です。AI が自然にこの戦略を選択した点は注目に値します。

結果 2: 並行処理課題で差が現れた

Thread Pool の結果です。指標の定義は次のとおりです。

  • Rounds to green: テスト全通過までに要した修正ラウンド数 (生成→ビルド→テスト→失敗提示→修正 を 1 ラウンドとする)
  • Compile-fix cycles: テスト実行前にコンパイルエラーで止まり修正した回数
  • Regression count: 修正により別のテストが新たに失敗した回数
指標 C C++ Rust Zig
First-pass result T08 失敗 ビルドエラー T08 失敗 ビルドエラー
Rounds to green 1 2 2 3
Compile-fix cycles 0 1 0 1
Regression count 0 0 1 0
Stress survival 全通過 全通過 全通過 全通過

課題 A とはうってかわって、全言語で修理が発生しました。修理ラウンド数は C: 1、C++: 2、Rust: 2、Zig: 3 です。

全言語共通の壁: テスト側のタイミングレース

4 言語すべてで T08 テスト (submit がブロック中に shutdown が呼ばれるケース) が失敗しました。原因は実装ロジックの誤りではなく、テストコード内のタイミング依存性です。AI は並行処理の実装ロジック自体は概ね正しく生成できましたが、テスト内で submit の完了を待ってから shutdown を呼ぶという制約を初回で正しく扱えませんでした。

言語ごとに異なる失敗の種類

T08 テスト側レースは全言語共通でしたが、それ以外の失敗は言語ごとに異なります。C はテスト側レースの修正のみで 1 ラウンド完了でしたが、他の 3 言語は追加の問題を抱えていました。

  • C++
    worker_loop を自由関数として定義したが、private な Impl 構造体にアクセスできずコンパイルエラー (C2248)
  • Zig
    Zig の API 変更により std.time.sleepstd.Thread.sleep に移動しておりコンパイルエラー。さらに ThreadPool を値返ししたことでワーカースレッドがダングリングポインタを参照しランタイムパニック
  • Rust
    T08 の修正が T09 をリグレッションさせた (修理中に別のテストを壊した唯一の言語)

Zig のランタイム検出が AI を助けた事例

Zig の R2 は興味深い事例です。ThreadPool を値で返すと、構造体がスタック上で移動し、ワーカースレッドが保持するポインタが無効になります。Zig のランタイム境界チェックがこれを index out of bounds として即座に検出し、AI は SharedState をヒープに配置する修正を 1 ラウンドで完了しました。

pub const ThreadPool = struct {
    state: *SharedState,  // ヒープへのポインタ (値埋め込みではない)
    workers: []std.Thread,

    pub fn init(thread_count: usize, queue_capacity: usize) ThreadPool {
        const alloc = std.heap.page_allocator;
        // SharedState をヒープに配置し、安定したアドレスを確保
        const state = alloc.create(SharedState) catch @panic("alloc failed");
        // ...
    }
};

Rust であればこの種の問題はコンパイル時に検出されますが、C であれば未定義動作として静かに進行する可能性があります。 Zig のランタイム検出は、コンパイル時保証がない言語でもエラーの早期発見に貢献した好例です。

結果 3: 理解度テストではどの言語のコードも正確に読めた

完成コードに対し、仕様書なしで別セッションの AI に 3 つのタスクを課しました。

  1. タスク 1: 概要説明
    実装の構造、同期方式、ライフサイクルなどの理解度を 7 項目で評価
  2. タスク 2: 問題点指摘
    指定関数の潜在的リスクを分析
  3. タスク 3: 機能追加
    新しい関数を追加実装させ、既存テストを壊さないか確認

結果は両課題とも全 4 言語でタスク 1: 7/7、タスク 2: 正確、タスク 3: 修理 0 ラウンドでした。実装時には課題 B で言語間の差が現れたにもかかわらず、読解と改修では差が出ませんでした。

ただしタスク 2 の指摘内容には質的な差がありました。課題 A の cache_get の参照無効化について、C/C++/Zig は use-after-free リスクとして指摘したのに対し、Rust は参照無効化がボローチェッカにより防がれることを認識したうえで、&mut self による API の使い勝手への制約として指摘しました。AI は言語の安全性モデルを理解したうえで、同じ問題を言語固有の文脈で再解釈しています。

検証から分かったこと

仮説 1, 2: ボローチェッカの影響

ボローチェッカが修理を助けるボローチェッカが AI を苦しめるという 2 つの仮説はどちらも当てはまりませんでした。Rust のコンパイルエラーは 0 回で、ボローチェッカに苦しめられた形跡はありません。課題 A ではインデックスベースリストを自然に選択するなど、最初から折り合いを付けていました。一方で修理ラウンドが最少でもなく (最少は C の 1 回)、唯一リグレッションが発生した言語でもありました。

仮説 3: C の単純さが有利にはたらくか

一部当てはまりました。課題 B で C は最少の 1 ラウンドで合格し、コンパイルエラーもランタイムパニックもなく、テスト側レースの修正のみで済んでいます。ただし課題 A では 4 言語とも差がなかったため、優位性は限定的です。

仮説 4: 生成品質に言語差なし

実態に最も近い仮説でした。 課題 A では完全に当てはまり、課題 B でも全言語共通のテスト側レースが支配的で、言語固有の差は相対的に小さいものでした。

仮説外の発見

C++ と Zig はコンパイル時にエラーを検出し、Zig はランタイムでもダングリングポインタを捕捉しました。Rust は unsafe なしでスレッド安全性を保証しました。しかし、テストのタイミングレースはいずれの安全機構でも防げませんでした。言語安全機構の効果は、エラーメッセージの速さと具体性に表れます。

まとめ

AI にとって言語の選択は生成品質にわずかな影響を与えますが、その影響は課題の複雑さに対して相対的に小さいものでした。 メモリ管理のような既知のパターンでは差が出ず、並行処理で初めて差が顕在化します。言語安全機構はエラーの早期検出に寄与しますが、テスト設計のタイミング制約は全 4 言語で修理を要しており、言語の選択では回避できない課題でした。

付録: プロンプト原文

各セッションに投入したプロンプトと仕様書の原文です。作業ディレクトリのパスは /path/to/project に置換しています。

課題 A: 実装セッション

C
# 指示: C 言語で LRU キャッシュを実装してください

## 背景

あなたは AI コード生成の実験に参加しています。与えられた仕様に基づき、C 言語で LRU キャッシュを実装してください。

## 作業ディレクトリ

`/path/to/project/c/task-a`

## 仕様

仕様書を読んでください: `/path/to/project/specs/task-a-lru-cache.md`

## 既存ファイル

以下のスケルトンファイルが用意されています。

- `src/lru_cache.h` — API のヘッダファイル (関数シグネチャ定義済み)
- `src/lru_cache.c` — 実装ファイル (スタブ。ここに実装を書く)
- `test/test_main.c` — L1 テスト (T01, T02 のみ実装済み。仕様書の T01-T12 を全て実装する)
- `test/stress_main.c` — L2 ストレステスト (実装済み)
- `CMakeLists.txt` — ビルド定義

## 手順

1. まず仕様書 (`specs/task-a-lru-cache.md`) を読む
2. 既存のヘッダファイル (`src/lru_cache.h`) のシグネチャを確認する
3. `src/lru_cache.c` に LRU キャッシュの完全な実装を書く
4. `test/test_main.c` に仕様書の T01-T12 のテストケースを全て実装する
5. ビルドしてテストを実行する
6. 失敗があれば修正する (最大 5 ラウンド)
7. L2 ストレステストを実行する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/c/task-a
cmake -B build -G "Visual Studio 17 2022"
cmake --build build --config Release
```

L1 テスト:
```
cd /path/to/project/c/task-a
./build/Release/test_main.exe
```

L2 ストレス:
```
cd /path/to/project/c/task-a
./build/Release/stress_main.exe --seed 12345
```

## 注意事項

- C17 標準、MSVC コンパイラを使用
- 外部依存なし (標準ライブラリのみ)
- ヘッダファイルの関数シグネチャは変更可能だが、変更した場合はテストとストレスコードも合わせて修正すること
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること

## 修理ルール

- テスト失敗時は、まず実装の誤りを疑うこと (テストを安易に修正しない)
- 最大 5 ラウンドで修理する。5 ラウンドで合格しなければ、その時点の状態で終了する
- 各ラウンドで何を修正したか、結果がどうだったかを報告すること
C++
# 指示: C++ で LRU キャッシュを実装してください

## 背景

あなたは AI コード生成の実験に参加しています。与えられた仕様に基づき、C++ で LRU キャッシュを実装してください。

## 作業ディレクトリ

`/path/to/project/cpp/task-a`

## 仕様

仕様書を読んでください: `/path/to/project/specs/task-a-lru-cache.md`

## 既存ファイル

以下のスケルトンファイルが用意されています。

- `src/lru_cache.hpp` — API のヘッダファイル (クラス定義済み)
- `src/lru_cache.cpp` — 実装ファイル (スタブ。ここに実装を書く)
- `test/test_main.cpp` — L1 テスト (T01, T02 のみ実装済み。仕様書の T01-T12 を全て実装する)
- `test/stress_main.cpp` — L2 ストレステスト (実装済み)
- `CMakeLists.txt` — ビルド定義

## 手順

1. まず仕様書 (`specs/task-a-lru-cache.md`) を読む
2. 既存のヘッダファイル (`src/lru_cache.hpp`) のクラス定義を確認する
3. `src/lru_cache.cpp` (およびヘッダ) に LRU キャッシュの完全な実装を書く
4. `test/test_main.cpp` に仕様書の T01-T12 のテストケースを全て実装する
5. ビルドしてテストを実行する
6. 失敗があれば修正する (最大 5 ラウンド)
7. L2 ストレステストを実行する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/cpp/task-a
cmake -B build -G "Visual Studio 17 2022"
cmake --build build --config Release
```

L1 テスト:
```
cd /path/to/project/cpp/task-a
./build/Release/test_main.exe
```

L2 ストレス:
```
cd /path/to/project/cpp/task-a
./build/Release/stress_main.exe --seed 12345
```

## 注意事項

- C++17 標準、MSVC コンパイラを使用 (std::span は使用不可)
- 外部依存なし (標準ライブラリのみ)
- ヘッダファイルのクラス定義は変更可能だが、変更した場合はテストとストレスコードも合わせて修正すること
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること

## 修理ルール

- テスト失敗時は、まず実装の誤りを疑うこと (テストを安易に修正しない)
- 最大 5 ラウンドで修理する。5 ラウンドで合格しなければ、その時点の状態で終了する
- 各ラウンドで何を修正したか、結果がどうだったかを報告すること
Rust
# 指示: Rust で LRU キャッシュを実装してください

## 背景

あなたは AI コード生成の実験に参加しています。与えられた仕様に基づき、Rust で LRU キャッシュを実装してください。

## 作業ディレクトリ

`/path/to/project/rust/task-a`

## 仕様

仕様書を読んでください: `/path/to/project/specs/task-a-lru-cache.md`

## 既存ファイル

以下のスケルトンファイルが用意されています。

- `src/lib.rs` — API 定義とスタブ実装 (ここに実装を書く)
- `tests/test_lru.rs` — L1 テスト (T01, T02 のみ実装済み。仕様書の T01-T12 を全て実装する)
- `tests/stress_lru.rs` — L2 ストレステスト (実装済み)
- `Cargo.toml` — プロジェクト定義

## 手順

1. まず仕様書 (`specs/task-a-lru-cache.md`) を読む
2. 既存の `src/lib.rs` の構造体と API を確認する
3. `src/lib.rs` に LRU キャッシュの完全な実装を書く
4. `tests/test_lru.rs` に仕様書の T01-T12 のテストケースを全て実装する
5. ビルドしてテストを実行する
6. 失敗があれば修正する (最大 5 ラウンド)
7. L2 ストレステストを実行する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/rust/task-a
cargo build
```

L1 テスト:
```
cd /path/to/project/rust/task-a
cargo test --test test_lru
```

L2 ストレス:
```
cd /path/to/project/rust/task-a
cargo test --test stress_lru
```

環境変数で seed を指定する場合:
```
cd /path/to/project/rust/task-a
STRESS_SEED=12345 cargo test --test stress_lru
```

## 注意事項

- Rust stable (1.93.1) を使用
- 外部依存なし (標準ライブラリのみ。Cargo.toml に依存を追加しない)
- 構造体定義や API のシグネチャは自由に変更してよいが、変更した場合はテストとストレスコードも合わせて修正すること
- 参照の寿命に関する設計 (ボローチェッカとの折り合い) は自由に選択してよい
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること

## 修理ルール

- テスト失敗時は、まず実装の誤りを疑うこと (テストを安易に修正しない)
- 最大 5 ラウンドで修理する。5 ラウンドで合格しなければ、その時点の状態で終了する
- 各ラウンドで何を修正したか、結果がどうだったかを報告すること
Zig
# 指示: Zig で LRU キャッシュを実装してください

## 背景

あなたは AI コード生成の実験に参加しています。与えられた仕様に基づき、Zig で LRU キャッシュを実装してください。

## 作業ディレクトリ

`/path/to/project/zig/task-a`

## 仕様

仕様書を読んでください: `/path/to/project/specs/task-a-lru-cache.md`

## 既存ファイル

以下のスケルトンファイルが用意されています。

- `src/root.zig` — API 定義とスタブ実装 (ここに実装を書く。T01, T02 のテストも含まれている)
- `src/main.zig` — L2 ストレステスト (実行ファイル。実装済み)
- `build.zig` — ビルド定義
- `build.zig.zon` — パッケージ定義

## 手順

1. まず仕様書 (`specs/task-a-lru-cache.md`) を読む
2. 既存の `src/root.zig` の構造体と API を確認する
3. `src/root.zig` に LRU キャッシュの完全な実装を書く
4. `src/root.zig` 内のテストブロックに仕様書の T01-T12 のテストケースを全て実装する (T01, T02 は既にある)
5. ビルドしてテストを実行する
6. 失敗があれば修正する (最大 5 ラウンド)
7. L2 ストレステストを実行する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/zig/task-a
zig build
```

L1 テスト:
```
cd /path/to/project/zig/task-a
zig build test
```

L2 ストレス (ビルドして実行):
```
cd /path/to/project/zig/task-a
zig build run -- --seed 12345
```

## 注意事項

- Zig 0.15.2 を使用
- 外部依存なし (標準ライブラリのみ)
- 構造体定義や API のシグネチャは自由に変更してよいが、変更した場合は `src/main.zig` (ストレステスト) も合わせて修正すること
- Zig 0.15.2 では `std.io.getStdOut()` は使用不可。`std.fs.File.stdout()` を使用すること
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること

## 修理ルール

- テスト失敗時は、まず実装の誤りを疑うこと (テストを安易に修正しない)
- 最大 5 ラウンドで修理する。5 ラウンドで合格しなければ、その時点の状態で終了する
- 各ラウンドで何を修正したか、結果がどうだったかを報告すること

課題 A: 理解度テスト

C
# 指示: C 言語の LRU キャッシュ実装を理解し改修してください

## 背景

あなたはコード理解度テストに参加しています。他者が実装した C 言語の LRU キャッシュを読み解き、分析と改修を行ってください。仕様書は提供されません。コードそのものから仕様を理解してください。

## 作業ディレクトリ

`/path/to/project/c/task-a`

## 対象ファイル

- `src/lru_cache.h` — ヘッダファイル (API 定義)
- `src/lru_cache.c` — 実装ファイル
- `test/test_main.c` — テストコード (T01-T12)

## タスク

以下の 3 つのタスクを順番に実行してください。

### タスク 1: 実装の概要説明

コードを読み、この LRU キャッシュの実装について概要を説明してください。以下の観点を含めてください。

- 使用しているデータ構造
- 各 API 関数の振る舞い
- 値の所有権とメモリ管理の方針
- 計算量

### タスク 2: cache_get の潜在的問題点

`cache_get` 関数を分析し、潜在的な問題点やリスクを指摘してください。安全性、正確性、堅牢性の観点から検討してください。

### タスク 3: cache_clear() の追加実装

キャッシュ内の全エントリを削除する `cache_clear` 関数を追加実装してください。キャッシュ自体は破棄せず、空の状態で再利用可能にしてください。

具体的には:
1. `src/lru_cache.h` にシグネチャを追加する
2. `src/lru_cache.c` に実装を追加する
3. 既存のテスト (T01-T12) が引き続き全て通過することを確認する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/c/task-a
cmake -B build -G "Visual Studio 17 2022"
cmake --build build --config Release
```

L1 テスト:
```
cd /path/to/project/c/task-a
./build/Release/test_main.exe
```

## 注意事項

- C17 標準、MSVC コンパイラを使用
- 外部依存なし (標準ライブラリのみ)
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること
- 既存のコードスタイルに合わせること
C++
# 指示: C++ の LRU キャッシュ実装を理解し改修してください

## 背景

あなたはコード理解度テストに参加しています。他者が実装した C++ の LRU キャッシュを読み解き、分析と改修を行ってください。仕様書は提供されません。コードそのものから仕様を理解してください。

## 作業ディレクトリ

`/path/to/project/cpp/task-a`

## 対象ファイル

- `src/lru_cache.hpp` — ヘッダファイル (クラス定義)
- `src/lru_cache.cpp` — 実装ファイル
- `test/test_main.cpp` — テストコード (T01-T12)

## タスク

以下の 3 つのタスクを順番に実行してください。

### タスク 1: 実装の概要説明

コードを読み、この LRU キャッシュの実装について概要を説明してください。以下の観点を含めてください。

- 使用しているデータ構造
- 各 API 関数 (メソッド) の振る舞い
- 値の所有権とメモリ管理の方針
- 計算量

### タスク 2: get メソッドの潜在的問題点

`get` メソッドを分析し、潜在的な問題点やリスクを指摘してください。安全性、正確性、堅牢性の観点から検討してください。

### タスク 3: clear() メソッドの追加実装

キャッシュ内の全エントリを削除する `clear` メソッドを追加実装してください。キャッシュ自体は破棄せず、空の状態で再利用可能にしてください。

具体的には:
1. `src/lru_cache.hpp` にメソッド宣言を追加する
2. `src/lru_cache.cpp` に実装を追加する
3. 既存のテスト (T01-T12) が引き続き全て通過することを確認する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/cpp/task-a
cmake -B build -G "Visual Studio 17 2022"
cmake --build build --config Release
```

L1 テスト:
```
cd /path/to/project/cpp/task-a
./build/Release/test_main.exe
```

## 注意事項

- C++17 標準、MSVC コンパイラを使用 (std::span は使用不可)
- 外部依存なし (標準ライブラリのみ)
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること
- 既存のコードスタイルに合わせること
Rust
# 指示: Rust の LRU キャッシュ実装を理解し改修してください

## 背景

あなたはコード理解度テストに参加しています。他者が実装した Rust の LRU キャッシュを読み解き、分析と改修を行ってください。仕様書は提供されません。コードそのものから仕様を理解してください。

## 作業ディレクトリ

`/path/to/project/rust/task-a`

## 対象ファイル

- `src/lib.rs` — 実装ファイル
- `tests/test_lru.rs` — テストコード (T01-T12)

## タスク

以下の 3 つのタスクを順番に実行してください。

### タスク 1: 実装の概要説明

コードを読み、この LRU キャッシュの実装について概要を説明してください。以下の観点を含めてください。

- 使用しているデータ構造
- 各 API 関数 (メソッド) の振る舞い
- 値の所有権とメモリ管理の方針
- 計算量

### タスク 2: get メソッドの潜在的問題点

`get` メソッドを分析し、潜在的な問題点やリスクを指摘してください。安全性、正確性、堅牢性の観点から検討してください。

### タスク 3: clear() メソッドの追加実装

キャッシュ内の全エントリを削除する `clear` メソッドを追加実装してください。キャッシュ自体は破棄せず、空の状態で再利用可能にしてください。

具体的には:
1. `src/lib.rs` に `clear` メソッドを追加する
2. 既存のテスト (T01-T12) が引き続き全て通過することを確認する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/rust/task-a
cargo build
```

L1 テスト:
```
cd /path/to/project/rust/task-a
cargo test --test test_lru
```

## 注意事項

- Rust stable (1.93.1) を使用
- 外部依存なし (標準ライブラリのみ。Cargo.toml に依存を追加しない)
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること
- 既存のコードスタイルに合わせること
Zig
# 指示: Zig の LRU キャッシュ実装を理解し改修してください

## 背景

あなたはコード理解度テストに参加しています。他者が実装した Zig の LRU キャッシュを読み解き、分析と改修を行ってください。仕様書は提供されません。コードそのものから仕様を理解してください。

## 作業ディレクトリ

`/path/to/project/zig/task-a`

## 対象ファイル

- `src/root.zig` — 実装ファイル (テストブロックも含む)

## タスク

以下の 3 つのタスクを順番に実行してください。

### タスク 1: 実装の概要説明

コードを読み、この LRU キャッシュの実装について概要を説明してください。以下の観点を含めてください。

- 使用しているデータ構造
- 各 API 関数の振る舞い
- 値の所有権とメモリ管理の方針
- 計算量

### タスク 2: get 関数の潜在的問題点

`get` 関数を分析し、潜在的な問題点やリスクを指摘してください。安全性、正確性、堅牢性の観点から検討してください。

### タスク 3: clear() 関数の追加実装

キャッシュ内の全エントリを削除する `clear` 関数を追加実装してください。キャッシュ自体は破棄 (deinit) せず、空の状態で再利用可能にしてください。

具体的には:
1. `src/root.zig` の LRUCache 構造体に `clear` メソッドを追加する
2. 既存のテスト (T01-T12) が引き続き全て通過することを確認する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/zig/task-a
zig build
```

L1 テスト:
```
cd /path/to/project/zig/task-a
zig build test
```

## 注意事項

- Zig 0.15.2 を使用
- 外部依存なし (標準ライブラリのみ)
- Zig 0.15.2 では `std.io.getStdOut()` は使用不可。`std.fs.File.stdout()` を使用すること
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること
- 既存のコードスタイルに合わせること

課題 B: 実装セッション

C
# 指示: C 言語で Bounded Thread Pool を実装してください

## 背景

あなたは AI コード生成の実験に参加しています。与えられた仕様に基づき、C 言語でスレッドプールを実装してください。

## 作業ディレクトリ

`/path/to/project/c/task-b`

## 仕様

仕様書を読んでください: `/path/to/project/specs/task-b-thread-pool.md`

## 既存ファイル

以下のスケルトンファイルが用意されています。

- `src/thread_pool.h` — API のヘッダファイル (型と関数シグネチャ定義済み)
- `src/thread_pool.c` — 実装ファイル (スタブ。ここに実装を書く)
- `test/test_main.c` — L1 テスト (T01, T02 のみ実装済み。仕様書の T01-T12 を全て実装する)
- `test/stress_main.c` — L2 ストレステスト (実装済み)
- `CMakeLists.txt` — ビルド定義

## 手順

1. まず仕様書 (`specs/task-b-thread-pool.md`) を読む
2. 既存のヘッダファイル (`src/thread_pool.h`) のシグネチャを確認する
3. `src/thread_pool.c` にスレッドプールの完全な実装を書く
4. `test/test_main.c` に仕様書の T01-T12 のテストケースを全て実装する
5. ビルドしてテストを実行する
6. 失敗があれば修正する (最大 5 ラウンド)
7. L2 ストレステストを実行する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/c/task-b
cmake -B build -G "Visual Studio 17 2022"
cmake --build build --config Release
```

L1 テスト:
```
cd /path/to/project/c/task-b
./build/Release/test_main.exe
```

L2 ストレス:
```
cd /path/to/project/c/task-b
./build/Release/stress_main.exe --seed 12345
```

## 注意事項

- C17 標準、MSVC コンパイラを使用
- 外部依存なし (標準ライブラリ + Windows API のみ)
- スレッド同期には Windows API (`CreateThread`, `CRITICAL_SECTION`, `CONDITION_VARIABLE`) または C11 `<threads.h>` を使用可能。AI の選択に委ねる
- ヘッダファイルの関数シグネチャは変更可能だが、変更した場合はテストとストレスコードも合わせて修正すること
- テスト内で `InterlockedAdd` を使用している。`<windows.h>` のインクルードが必要
- gate パターン (mutex + condvar + opened フラグ) はテスト内にヘルパーとして実装すること
- T08, T09 では別スレッドから submit するテストがある。Windows API の `CreateThread` 等でテスト用スレッドを起動すること
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること

## 修理ルール

- テスト失敗時は、まず実装の誤りを疑うこと (テストを安易に修正しない)
- 最大 5 ラウンドで修理する。5 ラウンドで合格しなければ、その時点の状態で終了する
- 各ラウンドで何を修正したか、結果がどうだったかを報告すること
C++
# 指示: C++ で Bounded Thread Pool を実装してください

## 背景

あなたは AI コード生成の実験に参加しています。与えられた仕様に基づき、C++ でスレッドプールを実装してください。

## 作業ディレクトリ

`/path/to/project/cpp/task-b`

## 仕様

仕様書を読んでください: `/path/to/project/specs/task-b-thread-pool.md`

## 既存ファイル

以下のスケルトンファイルが用意されています。

- `src/thread_pool.hpp` — API のヘッダファイル (クラス宣言定義済み)
- `src/thread_pool.cpp` — 実装ファイル (スタブ。ここに実装を書く)
- `test/test_main.cpp` — L1 テスト (T01, T02 のみ実装済み。仕様書の T01-T12 を全て実装する)
- `test/stress_main.cpp` — L2 ストレステスト (実装済み)
- `CMakeLists.txt` — ビルド定義

## 手順

1. まず仕様書 (`specs/task-b-thread-pool.md`) を読む
2. 既存のヘッダファイル (`src/thread_pool.hpp`) のクラス宣言を確認する
3. `src/thread_pool.cpp` にスレッドプールの完全な実装を書く
4. `test/test_main.cpp` に仕様書の T01-T12 のテストケースを全て実装する
5. ビルドしてテストを実行する
6. 失敗があれば修正する (最大 5 ラウンド)
7. L2 ストレステストを実行する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/cpp/task-b
cmake -B build -G "Visual Studio 17 2022"
cmake --build build --config Release
```

L1 テスト:
```
cd /path/to/project/cpp/task-b
./build/Release/test_main.exe
```

L2 ストレス:
```
cd /path/to/project/cpp/task-b
./build/Release/stress_main.exe --seed 12345
```

## 注意事項

- C++17 標準、MSVC コンパイラを使用
- 外部依存なし (標準ライブラリのみ)
- スレッド同期には `<thread>`, `<mutex>`, `<condition_variable>` 等の C++17 標準ライブラリを使用すること
- `pool_destroy` は不要 (デストラクタで解放する)。デストラクタでは join 完了後にリソースを解放すること
- クラス宣言や API のシグネチャは自由に変更してよいが、変更した場合はテストとストレスコードも合わせて修正すること
- gate パターン (mutex + condvar + opened フラグ) はテスト内にヘルパーとして実装すること
- T08, T09 では別スレッドから submit するテストがある。`std::thread` でテスト用スレッドを起動すること
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること

## 修理ルール

- テスト失敗時は、まず実装の誤りを疑うこと (テストを安易に修正しない)
- 最大 5 ラウンドで修理する。5 ラウンドで合格しなければ、その時点の状態で終了する
- 各ラウンドで何を修正したか、結果がどうだったかを報告すること
Rust
# 指示: Rust で Bounded Thread Pool を実装してください

## 背景

あなたは AI コード生成の実験に参加しています。与えられた仕様に基づき、Rust でスレッドプールを実装してください。

## 作業ディレクトリ

`/path/to/project/rust/task-b`

## 仕様

仕様書を読んでください: `/path/to/project/specs/task-b-thread-pool.md`

## 既存ファイル

以下のスケルトンファイルが用意されています。

- `src/lib.rs` — API 定義とスタブ実装 (ここに実装を書く)
- `tests/test_pool.rs` — L1 テスト (T01, T02 のみ実装済み。仕様書の T01-T12 を全て実装する)
- `tests/stress_pool.rs` — L2 ストレステスト (実装済み)
- `Cargo.toml` — プロジェクト定義

## 手順

1. まず仕様書 (`specs/task-b-thread-pool.md`) を読む
2. 既存の `src/lib.rs` の構造体と API を確認する
3. `src/lib.rs` にスレッドプールの完全な実装を書く
4. `tests/test_pool.rs` に仕様書の T01-T12 のテストケースを全て実装する
5. ビルドしてテストを実行する
6. 失敗があれば修正する (最大 5 ラウンド)
7. L2 ストレステストを実行する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/rust/task-b
cargo build
```

L1 テスト:
```
cd /path/to/project/rust/task-b
cargo test --test test_pool
```

L2 ストレス:
```
cd /path/to/project/rust/task-b
cargo test --test stress_pool
```

環境変数で seed を指定する場合:
```
cd /path/to/project/rust/task-b
STRESS_SEED=12345 cargo test --test stress_pool
```

## 注意事項

- Rust stable を使用
- 外部依存なし (標準ライブラリのみ。Cargo.toml に依存を追加しない)
- `pool_destroy` は不要 (`Drop` トレイトで解放する)
- タスク関数の型 (`fn(i32)` またはクロージャ) は自由に選択してよい
- 構造体定義や API のシグネチャは自由に変更してよいが、変更した場合はテストとストレスコードも合わせて修正すること
- gate パターン (Mutex + Condvar + opened フラグ) はテスト内にヘルパーとして実装すること
- T08, T09 では別スレッドから submit するテストがある。`std::thread::spawn` でテスト用スレッドを起動すること
- スレッドプールの `submit` は `&self` で受け取ること (`Arc` でラップしてスレッド間共有する)
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること

## 修理ルール

- テスト失敗時は、まず実装の誤りを疑うこと (テストを安易に修正しない)
- 最大 5 ラウンドで修理する。5 ラウンドで合格しなければ、その時点の状態で終了する
- 各ラウンドで何を修正したか、結果がどうだったかを報告すること
Zig
# 指示: Zig で Bounded Thread Pool を実装してください

## 背景

あなたは AI コード生成の実験に参加しています。与えられた仕様に基づき、Zig でスレッドプールを実装してください。

## 作業ディレクトリ

`/path/to/project/zig/task-b`

## 仕様

仕様書を読んでください: `/path/to/project/specs/task-b-thread-pool.md`

## 既存ファイル

以下のスケルトンファイルが用意されています。

- `src/root.zig` — API 定義 + L1 テスト (T01, T02 のみ実装済み。仕様書の T01-T12 を全て実装する)
- `src/main.zig` — L2 ストレステスト (実装済み)
- `build.zig` — ビルド定義
- `build.zig.zon` — パッケージ定義

## 手順

1. まず仕様書 (`specs/task-b-thread-pool.md`) を読む
2. 既存の `src/root.zig` の構造体と API を確認する
3. `src/root.zig` にスレッドプールの完全な実装を書く
4. `src/root.zig` に仕様書の T01-T12 のテストケースを全て実装する
5. ビルドしてテストを実行する
6. 失敗があれば修正する (最大 5 ラウンド)
7. L2 ストレステストを実行する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/zig/task-b
zig build
```

L1 テスト:
```
cd /path/to/project/zig/task-b
zig build test
```

L2 ストレス:
```
cd /path/to/project/zig/task-b
zig build run -- --seed 12345
```

## 注意事項

- Zig 0.15.2 を使用
- 外部依存なし (標準ライブラリのみ)
- `pool_destroy` は `deinit()` メソッドとして実装する
- スレッド同期には `std.Thread.Mutex` と `std.Thread.Condition` を使用すること
- ワーカースレッドの起動には `std.Thread.spawn` を使用すること
- 構造体定義や API のシグネチャは自由に変更してよいが、変更した場合はテストとストレスコードも合わせて修正すること
- gate パターン (Mutex + Condition + opened フラグ) はテスト内にヘルパーとして実装すること
- T08, T09 では別スレッドから submit するテストがある。`std.Thread.spawn` でテスト用スレッドを起動すること
- Zig 0.15.2 の IO API に注意: `std.fs.File.stdout().writer(&buf)` を使うこと (`std.io.getStdOut()` は使えない)
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること

## 修理ルール

- テスト失敗時は、まず実装の誤りを疑うこと (テストを安易に修正しない)
- 最大 5 ラウンドで修理する。5 ラウンドで合格しなければ、その時点の状態で終了する
- 各ラウンドで何を修正したか、結果がどうだったかを報告すること

課題 B: 理解度テスト

C
# 指示: C 言語の Thread Pool 実装を理解し改修してください

## 背景

あなたはコード理解度テストに参加しています。他者が実装した C 言語の Thread Pool を読み解き、分析と改修を行ってください。仕様書は提供されません。コードそのものから仕様を理解してください。

## 作業ディレクトリ

`/path/to/project/c/task-b`

## 対象ファイル

- `src/thread_pool.h` — ヘッダファイル (API 定義)
- `src/thread_pool.c` — 実装ファイル
- `test/test_main.c` — テストコード (T01-T12)

## タスク

以下の 3 つのタスクを順番に実行してください。

### タスク 1: 実装の概要説明

コードを読み、この Thread Pool の実装について概要を説明してください。以下の観点を含めてください。

- スレッドプールの全体構造
- 各 API 関数の振る舞い
- 同期機構とスレッド安全性の方針
- タスクキューの管理方法

### タスク 2: pool_submit の潜在的問題点

`pool_submit` 関数を分析し、潜在的な問題点やリスクを指摘してください。安全性、正確性、堅牢性の観点から検討してください。

### タスク 3: pool_drain() の追加実装

キュー内の未実行タスクをすべて除去する `pool_drain` 関数を追加実装してください。除去したタスクの数を返してください。プールは shutdown せず、引き続き submit を受け付けられる状態を維持してください。

具体的には以下の通りです。
1. `src/thread_pool.h` にシグネチャ `int pool_drain(ThreadPool *pool)` を追加する
2. `src/thread_pool.c` に実装を追加する
3. 既存のテスト (T01-T12) が引き続き全て通過することを確認する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/c/task-b
cmake -B build -G "Visual Studio 17 2022"
cmake --build build --config Release
```

L1 テスト:
```
cd /path/to/project/c/task-b
./build/Release/test_main.exe
```

## 注意事項

- C17 標準、MSVC コンパイラを使用
- 外部依存なし (標準ライブラリのみ)
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること
- 既存のコードスタイルに合わせること
C++
# 指示: C++ の Thread Pool 実装を理解し改修してください

## 背景

あなたはコード理解度テストに参加しています。他者が実装した C++ の Thread Pool を読み解き、分析と改修を行ってください。仕様書は提供されません。コードそのものから仕様を理解してください。

## 作業ディレクトリ

`/path/to/project/cpp/task-b`

## 対象ファイル

- `src/thread_pool.hpp` — ヘッダファイル (クラス定義)
- `src/thread_pool.cpp` — 実装ファイル
- `test/test_main.cpp` — テストコード (T01-T12)

## タスク

以下の 3 つのタスクを順番に実行してください。

### タスク 1: 実装の概要説明

コードを読み、この Thread Pool の実装について概要を説明してください。以下の観点を含めてください。

- スレッドプールの全体構造
- 各 API 関数 (メソッド) の振る舞い
- 同期機構とスレッド安全性の方針
- タスクキューの管理方法

### タスク 2: submit メソッドの潜在的問題点

`submit` メソッドを分析し、潜在的な問題点やリスクを指摘してください。安全性、正確性、堅牢性の観点から検討してください。

### タスク 3: drain() メソッドの追加実装

キュー内の未実行タスクをすべて除去する `drain` メソッドを追加実装してください。除去したタスクの数を返してください。プールは shutdown せず、引き続き submit を受け付けられる状態を維持してください。

具体的には以下の通りです。
1. `src/thread_pool.hpp` にメソッド宣言 `int drain()` を追加する
2. `src/thread_pool.cpp` に実装を追加する
3. 既存のテスト (T01-T12) が引き続き全て通過することを確認する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/cpp/task-b
cmake -B build -G "Visual Studio 17 2022"
cmake --build build --config Release
```

L1 テスト:
```
cd /path/to/project/cpp/task-b
./build/Release/test_main.exe
```

## 注意事項

- C++17 標準、MSVC コンパイラを使用 (std::span は使用不可)
- 外部依存なし (標準ライブラリのみ)
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること
- 既存のコードスタイルに合わせること
Rust
# 指示: Rust の Thread Pool 実装を理解し改修してください

## 背景

あなたはコード理解度テストに参加しています。他者が実装した Rust の Thread Pool を読み解き、分析と改修を行ってください。仕様書は提供されません。コードそのものから仕様を理解してください。

## 作業ディレクトリ

`/path/to/project/rust/task-b`

## 対象ファイル

- `src/lib.rs` — 実装ファイル
- `tests/test_pool.rs` — テストコード (T01-T12)

## タスク

以下の 3 つのタスクを順番に実行してください。

### タスク 1: 実装の概要説明

コードを読み、この Thread Pool の実装について概要を説明してください。以下の観点を含めてください。

- スレッドプールの全体構造
- 各 API 関数 (メソッド) の振る舞い
- 同期機構とスレッド安全性の方針
- タスクキューの管理方法

### タスク 2: submit メソッドの潜在的問題点

`submit` メソッドを分析し、潜在的な問題点やリスクを指摘してください。安全性、正確性、堅牢性の観点から検討してください。

### タスク 3: drain() メソッドの追加実装

キュー内の未実行タスクをすべて除去する `drain` メソッドを追加実装してください。除去したタスクの数を返してください。プールは shutdown せず、引き続き submit を受け付けられる状態を維持してください。

具体的には以下の通りです。
1. `src/lib.rs` に `pub fn drain(&self) -> usize` メソッドを追加する
2. 既存のテスト (T01-T12) が引き続き全て通過することを確認する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/rust/task-b
cargo build
```

L1 テスト:
```
cd /path/to/project/rust/task-b
cargo test --test test_pool
```

## 注意事項

- Rust stable (1.93.1) を使用
- 外部依存なし (標準ライブラリのみ。Cargo.toml に依存を追加しない)
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること
- 既存のコードスタイルに合わせること
Zig
# 指示: Zig の Thread Pool 実装を理解し改修してください

## 背景

あなたはコード理解度テストに参加しています。他者が実装した Zig の Thread Pool を読み解き、分析と改修を行ってください。仕様書は提供されません。コードそのものから仕様を理解してください。

## 作業ディレクトリ

`/path/to/project/zig/task-b`

## 対象ファイル

- `src/root.zig` — 実装ファイル (テストブロックも含む)

## タスク

以下の 3 つのタスクを順番に実行してください。

### タスク 1: 実装の概要説明

コードを読み、この Thread Pool の実装について概要を説明してください。以下の観点を含めてください。

- スレッドプールの全体構造
- 各 API 関数の振る舞い
- 同期機構とスレッド安全性の方針
- タスクキューの管理方法

### タスク 2: submit 関数の潜在的問題点

`submit` 関数を分析し、潜在的な問題点やリスクを指摘してください。安全性、正確性、堅牢性の観点から検討してください。

### タスク 3: drain() 関数の追加実装

キュー内の未実行タスクをすべて除去する `drain` 関数を追加実装してください。除去したタスクの数を返してください。プールは shutdown せず、引き続き submit を受け付けられる状態を維持してください。

具体的には以下の通りです。
1. `src/root.zig` の ThreadPool 構造体に `pub fn drain(self: *ThreadPool) usize` メソッドを追加する
2. 既存のテスト (T01-T12) が引き続き全て通過することを確認する

## ビルドとテストのコマンド

ビルド:
```
cd /path/to/project/zig/task-b
zig build
```

L1 テスト:
```
cd /path/to/project/zig/task-b
zig build test
```

## 注意事項

- Zig 0.15.2 を使用
- 外部依存なし (標準ライブラリのみ)
- Zig 0.15.2 では `std.io.getStdOut()` は使用不可。`std.fs.File.stdout()` を使用すること
- コマンドを `&&` や `|` で連結しないこと。個別の Bash 呼び出しに分けること
- 既存のコードスタイルに合わせること

仕様書

課題 A: LRU キャッシュ仕様書
# 課題 A 仕様書: LRU キャッシュ

## 1. 概要

固定容量の LRU (Least Recently Used) キャッシュを実装する。キャッシュは整数キーとバイト列の値を格納し、容量超過時には最も長くアクセスされていないエントリを自動的に削除 (エビクト) する。

`cache_get()` は値のコピーではなく、キャッシュ内部のデータへの参照 (ポインタ/スライス/ビュー) を返す。この設計により、所有権と寿命の管理が各言語で異なる形で求められる。

## 2. 用語定義

| 用語 | 定義 |
|---|---|
| エントリ | キーと値の組 |
| エビクション | 容量超過時に最古のエントリを削除する操作 |
| LRU 順序 | 最後にアクセスされた時刻の昇順。`put` と `get` の両方がアクセスとして扱われる |
| 参照 | キャッシュ内部のデータへのポインタ、スライス、またはビュー |

## 3. API 定義

### 3.1 cache_create

```
cache_create(capacity: 正の整数) -> Cache
```

指定容量のキャッシュを生成する。capacity は 1 以上の整数でなければならない。

### 3.2 cache_put

```
cache_put(cache: Cache, key: 整数, value: バイト列) -> void
```

キーと値のペアをキャッシュに挿入する。

- 同一キーが既に存在する場合、値を上書きする。このとき旧エントリの値の領域は解放される
- キャッシュが容量上限に達している場合、LRU 順序で最古のエントリをエビクトしてから挿入する
- `put` はアクセスとして扱い、挿入されたエントリを LRU 順序の末尾 (最新) に移動する

### 3.3 cache_get

```
cache_get(cache: Cache, key: 整数) -> 参照 または エラー
```

キーに対応する値への参照を返す。

- キーが存在する場合、値への参照を返す。`get` はアクセスとして扱い、該当エントリを LRU 順序の末尾に移動する
- キーが存在しない場合、エラーを返す (NULL ポインタ、None、error 等、言語に適した方法)

**参照の有効期間:** 返された参照は、次に同一キャッシュに対する `cache_put` が呼ばれるまで有効である。`cache_put` はエビクションや上書きにより内部データの再配置を引き起こす可能性があるため、`cache_put` 後は以前に取得した全ての参照が無効となる。

> この制約は C/C++/Zig では呼び出し側の責任で守る必要があるが、Rust ではボローチェッカにより強制される可能性がある。言語ごとにどのような設計を選択するかは AI の自由とする。

### 3.4 cache_destroy

```
cache_destroy(cache: Cache) -> void
```

キャッシュを破棄し、全エントリの値の領域を解放する。

- `cache_destroy` 後にキャッシュへのいかなる操作も行ってはならない
- C/C++/Zig ではこの制約は呼び出し側の責任で守る。Rust では所有権の移動により強制される可能性がある

## 4. キーと値の型

| 要素 | 型 |
|---|---|
| キー | 32 ビット符号付き整数 (`int32_t`, `i32`, `i32` 等) |
| 値 | バイト列。格納時にキャッシュ側が内部バッファにコピーして所有する |

値のバイト列の長さは `put` 時に指定する。キャッシュは長さ情報を保持する。

## 5. 所有権と寿命のルール

### 5.1 値の所有権

`cache_put` の呼び出し時、値のバイト列はキャッシュ内部にコピーされる。呼び出し側が渡した元のバッファの所有権はキャッシュに移転しない (キャッシュが独自にコピーを持つ)。

### 5.2 参照の寿命

`cache_get` が返す参照は、キャッシュ内部のバッファを直接指す。この参照は以下の操作が行われた時点で無効となる。

- 同一キャッシュに対する `cache_put` (エビクションまたは上書きによる内部再配置)
- `cache_destroy`

無効な参照へのアクセスは未定義動作 (C/C++/Zig) またはコンパイルエラー (Rust) となる。

### 5.3 エントリの解放責務

エントリの値の領域はキャッシュが管理する。エビクション時と `cache_destroy` 時にキャッシュが解放する。呼び出し側がエントリの値を直接解放してはならない。

## 6. エラー処理

| 操作 | エラー条件 | 期待される振る舞い |
|---|---|---|
| `cache_get` | キーが存在しない | エラーを返す (NULL, None, error 等) |
| `cache_put` | なし (容量超過はエビクションで処理) | 常に成功 |
| `cache_destroy` | なし | 常に成功 |

メモリ確保失敗 (malloc 失敗等) の処理は言語ごとの慣例に従う。テストでは確保失敗は想定しない。

## 7. 境界条件

| # | 条件 | 期待される振る舞い |
|---|---|---|
| B1 | 容量 1 のキャッシュ | put するたびに前のエントリがエビクトされる |
| B2 | 空キャッシュへの get | エラーを返す |
| B3 | 同一キーへの上書き put | 値が更新される。容量は増えない |
| B4 | 容量上限での連続 put (全て異なるキー) | 最古のエントリが順にエビクトされる |
| B5 | get 後の LRU 順序変更 | get したエントリはエビクション順序の末尾に移動する |
| B6 | 値が空のバイト列 (長さ 0) | 正常に格納、取得できる |
| B7 | 大きな値 (例: 1,024 バイト) | 正常に格納、取得できる |

## 8-9. テストケースとストレステスト仕様

T01-T12 の擬似コードと L2 ストレステスト仕様は長大なため省略します。概要は本文の検証方法セクションを参照してください。
課題 B: Thread Pool 仕様書
# 課題 B 仕様書: Bounded Thread Pool

## 1. 概要

固定サイズのスレッドプールを実装する。スレッドプールは bounded キュー (上限付きキュー) を持ち、投入されたタスクをワーカースレッドが順次実行する。キューが満杯の場合、`pool_submit` は空きが出るまでブロックする。

graceful shutdown と immediate shutdown の 2 つの終了モードを提供し、終了処理の安全性と正確性が言語ごとにどう異なるかを観察する。

## 2. 用語定義

| 用語 | 定義 |
|---|---|
| ワーカースレッド | プール生成時に起動され、キューからタスクを取り出して実行するスレッド |
| タスク | 関数と引数の組。ワーカースレッドが実行する最小単位 |
| bounded キュー | 容量上限を持つ FIFO キュー。満杯時に投入がブロックされる |
| graceful shutdown | キュー内の未実行タスクを全て完了してから停止する終了モード |
| immediate shutdown | キュー内の未実行タスクを破棄し、実行中のタスクの完了のみ待つ終了モード |

## 3. API 定義

### 3.1 pool_create

```
pool_create(thread_count: 正の整数, queue_capacity: 正の整数) -> Pool
```

### 3.2 pool_submit

```
pool_submit(pool: Pool, fn: タスク関数, arg: int32_t) -> SubmitResult
```

- キューに空きがあり、shutdown されていない場合、タスクをキューに追加して OK を返す
- キューが満杯で、shutdown されていない場合、空きが出るか shutdown されるまでブロックする
- 既に shutdown されている場合、即座に REJECTED を返す

### 3.3 pool_shutdown

```
pool_shutdown(pool: Pool, mode: ShutdownMode) -> void
```

- GRACEFUL: キュー内の全タスクの実行完了後にワーカースレッドを停止
- IMMEDIATE: キュー内の未実行タスクを破棄。実行中のタスクの完了のみ待つ

shutdown は冪等である。

### 3.4 pool_join / 3.5 pool_destroy

全ワーカースレッドの終了を待機し、リソースを解放する。

## 4. タスクの型

| 言語 | タスク関数の型 |
|---|---|
| C | `void (*)(int32_t)` |
| C++ | `std::function<void(int32_t)>` |
| Rust | AI の選択に委ねる |
| Zig | `*const fn(i32) void` または同等の関数ポインタ型 |

## 5. テスト補助機構: gate パターン

gate は mutex + condvar + opened フラグで構成される。gate が閉じている間、タスクは gate の前でブロックする。テストが gate を開くと、ブロック中のタスクが実行を再開する。

## 6. 境界条件

| # | 条件 | 期待される振る舞い |
|---|---|---|
| B1 | タスクなしで shutdown | ハングせずに完了する |
| B2 | 単一ワーカー | 全タスクが順次実行される |
| B3 | キュー満杯時の submit | 空きが出るまでブロックする |
| B4 | ブロック中の submit が shutdown で解除 | REJECTED を返す |
| B5 | shutdown の冪等性 | 2 回呼んでもクラッシュしない |
| B6 | immediate 後の join | ハングせずに完了する |
| B7 | FIFO 順序 (単一ワーカー) | 投入順に実行される |

## 7-8. テストケースとストレステスト仕様

T01-T12 の擬似コードと L2 ストレステスト仕様は長大なため省略します。概要は本文の検証方法セクションを参照してください。

この記事をシェアする

FacebookHatena blogX

関連記事