# 通知設計書 15-Notification クラス

## 概要

本ドキュメントは、clangdのサポートモジュールにおける`Notification`クラスの設計仕様を記述する。スレッド間の同期通知機構として、あるスレッドから別のスレッドへのシグナル送信と待機を実現するスレッドセーフなフラグである。

### 本通知の処理概要

Notification クラスは、マルチスレッドプログラミングにおける基本的な同期プリミティブである。一度セット（notify）されると、そのフラグを待機（wait）しているすべてのスレッドに通知が伝わる。これは「完了通知」パターンの実装に使用される。

**業務上の目的・背景**：clangd（Language Server）は多数の非同期タスク（インデックス作成、コード補完、診断など）を並行処理する。これらのタスクが完了したことを他のスレッドに通知する必要がある場面が頻繁に発生する。Notificationクラスは、この完了通知パターンを安全かつ効率的に実装するための基盤を提供する。例えば、バックグラウンドでのインデックス作成が完了したことをメインスレッドに通知する際に使用される。

**通知の送信タイミング**：`notify()`メソッドが呼び出された時点で通知が行われる。一度セットされたフラグは永続的にセット状態を維持し、リセットはできない（one-shot notification）。既にセット済みの状態で`notify()`を呼び出しても、操作は無視される（no-op）。

**通知の受信者**：`wait()`または`wait(Deadline)`メソッドを呼び出して待機しているすべてのスレッドが受信者となる。`notify_all()`により、待機中の全スレッドが同時にウェイクアップされる。

**通知内容の概要**：通知自体にはペイロード（データ）は含まれない。単純な「完了」シグナルのみを伝達する。データを渡す必要がある場合は、別途共有変数やキューを使用する。

**期待されるアクション**：待機していたスレッドは、`wait()`から復帰した後、関連する処理を続行する。タイムアウト付きの`wait(Deadline)`の場合は、戻り値を確認して通知を受け取ったかタイムアウトしたかを判定する必要がある。

## 通知種別

スレッド間同期通知（C++ condition_variable ベース）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（mutex + condition_variable） |
| 優先度 | 即時（notify_allによるブロードキャスト） |
| リトライ | 該当なし（確実に配信される） |

### 送信先決定ロジック

`wait()`メソッドを呼び出して待機している全てのスレッドに対して通知される。`notify_all()`により、待機中の全スレッドが同時にウェイクアップされる。

## 通知テンプレート

### スレッド間通知の場合

| 項目 | 内容 |
|-----|------|
| 通知タイプ | フラグセット |
| ペイロード | なし（boolフラグのみ） |
| 永続性 | 永続（一度セットされたらリセット不可） |

### API仕様

```cpp
class Notification {
public:
  // フラグをセット。既にセット済みの場合はno-op
  void notify();

  // フラグがセットされるまでブロック（無期限待機）
  void wait() const;

  // フラグがセットされるかタイムアウトするまでブロック
  // 戻り値: true=通知受信、false=タイムアウト
  [[nodiscard]] bool wait(Deadline D) const;

private:
  bool Notified = false;
  mutable std::condition_variable CV;
  mutable std::mutex Mu;
};
```

### 添付ファイル

該当なし（プログラム内部の同期機構）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Notified | 通知フラグ | 内部状態（初期値false） | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| メソッド呼び出し | notify() | Notified == false | フラグ未セット時のみ実際のセット処理が行われる |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 既にNotified | フラグが既にtrueの場合、notify()はno-op |

## 処理フロー

### 送信フロー（notify）

```mermaid
flowchart TD
    A[notify呼び出し] --> B[mutex lock取得]
    B --> C[Notified = true]
    C --> D[CV.notify_all]
    D --> E[lock解放後に復帰]
    E --> F[notify完了]
```

### 受信フロー（wait）

```mermaid
flowchart TD
    A[wait呼び出し] --> B[mutex lock取得]
    B --> C{Notified?}
    C -->|true| D[即座に復帰]
    C -->|false| E[CV.wait]
    E --> F{Notified?}
    F -->|true| D
    F -->|false| E
    D --> G[lock解放]
    G --> H[wait完了]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（メモリ内同期機構）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| タイムアウト | wait(Deadline)でタイムアウト発生 | 戻り値falseで判定可能 |
| デッドロック | 不適切なmutex使用（設計不良） | 設計時に注意が必要 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 該当なし（wait自体がループ） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

即時（notify呼び出し時に同期的に配信）

## セキュリティ考慮事項

- スレッドセーフな実装（mutexによる保護）
- notify_all()でブロードキャストするため、待機スレッドが複数でも安全
- lock保持中にnotify_all()を呼び出し、wait()からの復帰後にNotificationオブジェクトが破棄されてもレースが発生しないよう設計

## 備考

- Notificationは一度セットされるとリセットできない（one-shot pattern）
- 複数回のnotify()呼び出しは安全（冪等）
- Deadlineクラスと組み合わせてタイムアウト付き待機が可能
- AsyncTaskRunner、Memoize、PeriodicThrottlerなど他の同期プリミティブと同じファイルで定義
- wait()内部ではspurious wakeup（疑似覚醒）対策としてループが使用される

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造（クラス定義）を理解する

まず、Notificationクラスのメンバ変数と公開APIを理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Threading.h | `clang-tools-extra/clangd/support/Threading.h` | Notificationクラスの定義（行91-103）を確認 |

**読解のコツ**: 行91の「threadsafe flag that is initially clear」というコメントが本質を表している。内部状態はbool Notified（初期値false）とmutex、condition_variableで構成される。

#### Step 2: notify()の実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Threading.cpp | `clang-tools-extra/clangd/support/Threading.cpp` | notify()メソッドの実装（行28-36）を確認 |

**主要処理フロー**:
1. **行30**: `std::lock_guard<std::mutex> Lock(Mu)` でmutexをロック
2. **行31**: `Notified = true` でフラグをセット
3. **行33-34**: コメント - lock保持中にブロードキャストすることで、wait()からの復帰後にNotificationが破棄されてもレースが発生しない
4. **行34**: `CV.notify_all()` で待機中の全スレッドを起床

#### Step 3: wait()の実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Threading.h | `clang-tools-extra/clangd/support/Threading.h` | wait()の2つのオーバーロード（行96-97）を確認 |
| 3-2 | Threading.cpp | `clang-tools-extra/clangd/support/Threading.cpp` | wait(Deadline)の実装（行38-41）を確認 |

**主要処理フロー**:
- **行96**: `void wait() const { (void)wait(Deadline::infinity()); }` - 無期限待機はDeadline::infinityを渡すだけ
- **行38-41**: wait(Deadline)の実装
  - **行39**: `std::unique_lock<std::mutex> Lock(Mu)` でmutexをロック
  - **行40**: `clangd::wait(Lock, CV, D, [&] { return Notified; })` でヘルパー関数を呼び出し

#### Step 4: waitヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Threading.h | `clang-tools-extra/clangd/support/Threading.h` | テンプレートwait関数（行79-88）を確認 |

**主要処理フロー**:
- **行80-87**: ループ内でF()（Notified確認）をチェックし、trueならtrue返却
- **行83-84**: タイムアウト判定 - D.expired()がtrueならfalse返却
- **行85**: `wait(Lock, CV, D)` で条件変数待機

#### Step 5: Deadlineクラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Threading.h | `clang-tools-extra/clangd/support/Threading.h` | Deadlineクラスの定義（行46-71）を確認 |

**主要処理フロー**:
- **行50-51**: `zero()`と`infinity()`の静的ファクトリメソッド
- **行57-60**: `expired()`メソッドでタイムアウト判定
- **行66-70**: 内部でZero/Infinite/Finiteの3状態を管理

### プログラム呼び出し階層図

```
Notification::notify()
    │
    ├─ std::lock_guard<std::mutex> Lock(Mu)
    │
    ├─ Notified = true
    │
    └─ CV.notify_all()


Notification::wait() / wait(Deadline D)
    │
    ├─ std::unique_lock<std::mutex> Lock(Mu)
    │
    └─ clangd::wait(Lock, CV, D, [&]{ return Notified; })
           │
           ├─ ループ: !F() の間
           │      │
           │      ├─ D.expired() → false返却（タイムアウト）
           │      │
           │      └─ ::wait(Lock, CV, D)
           │             │
           │             └─ CV.wait() / CV.wait_until()
           │
           └─ F() == true → true返却（通知受信）
```

### データフロー図

```
[送信側スレッド]                    [受信側スレッド]

notify()呼び出し                    wait()呼び出し
    │                                   │
    ▼                                   ▼
mutex lock ◄─────────────────────── mutex lock待ち
    │                                   │
    ▼                                   ▼
Notified = true                     while(!Notified)
    │                                   │
    ▼                                   ▼
CV.notify_all() ─────────────────► CV.wait()から復帰
    │                                   │
    ▼                                   ▼
mutex unlock                        mutex unlock
    │                                   │
    ▼                                   ▼
notify()完了                        wait()完了
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Threading.h | `clang-tools-extra/clangd/support/Threading.h` | ヘッダー | Notification、Deadline、wait()テンプレートの定義 |
| Threading.cpp | `clang-tools-extra/clangd/support/Threading.cpp` | ソース | Notification::notify()、wait(Deadline)の実装 |
| Context.h | `clang-tools-extra/clangd/support/Context.h` | ヘッダー | Contextクラス定義（runAsyncで使用） |
| Trace.h | `clang-tools-extra/clangd/support/Trace.h` | ヘッダー | trace::Span定義（Semaphore::lockで使用） |
