# 機能設計書 117-SharedArrays

## 概要

本ドキュメントは、Julia標準ライブラリ `SharedArrays` モジュールの機能設計を記述する。共有メモリ配列（SharedArray）によるプロセス間共有メモリ機能を提供するモジュールである。

### 本機能の処理概要

**業務上の目的・背景**：マルチプロセス並列計算において、大規模データを複数のワーカープロセスで共有する必要がある場合、データのコピーを各プロセスに送ることはメモリ効率が悪く通信コストも高い。SharedArraysモジュールは、POSIX共有メモリ（shm_open）またはメモリマップドファイル（mmap）を使用して、同一ホスト上の複数プロセスが同じメモリ領域にアクセスできる共有配列を提供する。これにより、プロセス間通信のオーバーヘッドなしにデータを共有できる。

**機能の利用シーン**：マルチプロセス並列計算での大規模配列の共有、@distributedマクロとの組み合わせによるデータ並列処理、大規模シミュレーションにおけるプロセス間のデータ共有、ファイルバックの共有配列によるディスク永続化。

**主要な処理内容**：
1. SharedArray{T,N}の作成（メモリベース / ファイルベース）
2. 共有メモリセグメントの管理（shm_open / shm_unlink、Windows: Anonymous mmap）
3. プロセス間のデータ分割（localindices, indexpids）
4. 配列操作の分散実行（fill!, rand!, randn!, map!, reduce, copyto!）
5. シリアライゼーション/デシリアライゼーション（プロセス間転送用）
6. SharedVector、SharedMatrix型エイリアス

**関連システム・外部連携**：Distributedモジュール（マルチプロセス基盤）、Mmapモジュール（メモリマッピング）、Randomモジュール、Serializationモジュール。POSIX shm_open/shm_unlink、ftruncate。

**権限による制御**：共有メモリセグメントのアクセス権限はS_IRUSR | S_IWUSR（所有者読み書き）で作成される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | REPL | 参照画面 | SharedArrayの作成と操作 |

## 機能種別

データ共有 / 並列処理基盤

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| T | Type | Yes | 要素型 | isbitstype(T)がtrueであること |
| dims | NTuple{N,Int} | Yes | 配列の次元 | 正の整数のタプル |
| pids | Vector{Int} | No | マッピングするプロセスID。デフォルトはローカルホスト全プロセス | 同一ホスト上のプロセスであること |
| init | Function | No | 初期化関数 initfn(S::SharedArray) | SharedArrayを引数に取る関数 |
| filename | AbstractString | No (ファイルベース時) | バッキングファイルのパス | 絶対パスであること |
| offset | Integer | No | ファイル先頭からのオフセット | 非負整数 |
| mode | String | No | ファイルオープンモード（"r", "r+", "w+", "a+"） | 有効なモード文字列 |

### 入力データソース

- Distributedモジュールのプロセス情報
- ファイルシステム（ファイルバックの場合）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| S | SharedArray{T,N} | 共有メモリ配列。DenseArrayのサブタイプ |
| sdata(S) | Array{T,N} | バッキング配列の直接参照 |
| localindices(S) | UnitRange{Int} | 現在のワーカーの担当インデックス範囲 |
| indexpids(S) | Int | 現在のワーカーのpids内インデックス（0=マップなし） |

### 出力先

- 戻り値としてSharedArray型オブジェクトを返却
- 共有メモリセグメント（POSIX shm / mmap）
- ファイル（ファイルバック時）

## 処理フロー

### 処理シーケンス

```
1. SharedArray{T,N}(dims; pids=pids, init=init) 呼び出し
   └─ isbitstype(T) の検証
   └─ shared_pids()でプロセスリストの解決（同一ホスト検証）
   └─ 共有メモリセグメント名を生成
   └─ shm_mmap_array()で共有メモリ領域を作成・マッピング
   └─ 全ワーカープロセスにremoecall()でマッピングを配布
   └─ shm_unlink()でセグメント名をアンリンク（メモリは維持）
   └─ SharedArray構造体を構築
   └─ init関数があれば全ワーカーで実行
   └─ finalizerを登録

2. 配列アクセス
   └─ getindex/setindex! は内部のsフィールド（Array{T,N}）に委譲
   └─ 通常の配列と同様にアクセス可能

3. 分散操作（fill!, rand!, map!等）
   └─ @syncと@asyncで全ワーカーのloc_subarr_1dに対して並列実行
```

### フローチャート

```mermaid
flowchart TD
    A["SharedArray{T,N}(dims; pids, init)"] --> B{"isbitstype(T)?"}
    B -->|No| C["ArgumentError"]
    B -->|Yes| D["shared_pids()でプロセス解決"]
    D --> E["共有メモリセグメント作成"]
    E --> F["全ワーカーにマッピング配布"]
    F --> G["shm_unlink()"]
    G --> H["SharedArray構造体構築"]
    H --> I{"init関数あり?"}
    I -->|Yes| J["全ワーカーでinit実行"]
    I -->|No| K["finalizer登録"]
    J --> K
    K --> L["SharedArray返却"]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-117-01 | isbitstype制約 | 要素型はisbitstype(T)がtrueである必要がある | SharedArray作成時 |
| BR-117-02 | 同一ホスト制約 | 全てのpidsは同一ホスト上のプロセスである必要がある | SharedArray作成時 |
| BR-117-03 | ファイルパス絶対 | ファイルバックの場合、パスは絶対パスでなければならない | ファイルバックSharedArray作成時 |
| BR-117-04 | データ分割 | localindices()で各ワーカーに均等にインデックスを分配 | 分散操作時 |
| BR-117-05 | 早期アンリンク | 共有メモリセグメントは全ワーカーがマッピング後すぐにアンリンク | セグメント管理 |

### 計算ロジック

- データ分割: `partlen = div(length(S), nw)` で均等分割。最後のワーカーが残りを担当
- ワーカーインデックス範囲: `((pidx-1) * partlen + 1):(pidx * partlen)` （最終ワーカー以外）

## データベース操作仕様

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ArgumentError | 型制約違反 | isbitstype(T)がfalseの場合 | bits型を使用（Float64, Int等） |
| ArgumentError | ホスト制約違反 | pidsが異なるホストのプロセスを含む場合 | 同一ホストのプロセスのみ指定 |
| ArgumentError | パス制約違反 | ファイルバックで相対パスを指定した場合 | abspath()で絶対パスに変換 |
| SystemError | shm_open失敗 | 共有メモリセグメントの作成に失敗 | システムのshmem制限を確認 |

### リトライ仕様

リトライ不要。shm_open失敗時はprint_shmem_limits()でシステム制限情報を表示する。

## トランザクション仕様

該当なし。SharedArrayの操作はトランザクション制御を持たない。同時書き込みの排他制御はユーザーの責任。

## パフォーマンス要件

- 共有メモリアクセスはプロセスローカル配列とほぼ同等のパフォーマンス
- プロセス間通信（remotecall等）のオーバーヘッドはSharedArray作成時のみ発生
- 大規模配列の分散fill!/rand!は線形スケーリングが期待できる

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

- 共有メモリセグメントはS_IRUSR | S_IWUSRで作成（所有者のみ読み書き可能）
- セグメント名はランダム文字列を含む（`/jl{pid}{random20}` 形式）
- マッピング後すぐにshm_unlinkされるため、名前による外部アクセスは困難

## 備考

- SharedArraysはDistributedパッケージに依存しており、Distributed.jlのロード後に利用可能
- macOSではshm_seg_nameの長さ制限が31文字以下（NULL終端含む）
- Windowsではanonymous mmapで代替実装
- SharedVector = SharedArray{T,1}、SharedMatrix = SharedArray{T,2} 型エイリアスが定義されている

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

SharedArray構造体のフィールドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SharedArrays.jl | `stdlib/SharedArrays/src/SharedArrays.jl` | **22-49行目**: SharedArray{T,N}構造体の定義。id, dims, pids, refs, segname, s, pidx, loc_subarr_1dフィールド |

**読解のコツ**: SharedArrayは`mutable struct`であり、`s`フィールドがローカルのArray{T,N}バッキングを保持する。`pidx`は現在プロセスのpids内インデックス、`loc_subarr_1d`は現在プロセスが担当する1次元部分配列のビュー。

#### Step 2: エントリーポイントを理解する

SharedArray{T,N}コンストラクタがメインのエントリーポイント。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SharedArrays.jl | `stdlib/SharedArrays/src/SharedArrays.jl` | **105-161行目**: メモリベースのSharedArrayコンストラクタ。shm_mmap_array、remotecall、shm_unlinkの流れ |
| 2-2 | SharedArrays.jl | `stdlib/SharedArrays/src/SharedArrays.jl` | **176-238行目**: ファイルベースのSharedArrayコンストラクタ。Mmap.mmapを使用 |

**主要処理フロー**:
1. **106行目**: isbitstype(T)の検証
2. **108行目**: shared_pids()でプロセスリストの解決
3. **116行目**: セグメント名生成（/jl + PID + ランダム20文字）
4. **120行目**: shm_mmap_array()で共有メモリ作成
5. **132-135行目**: remotecall()で全ワーカーにマッピング配布
6. **145行目**: shm_unlink()でセグメント名削除
7. **151行目**: SharedArray構造体の構築
8. **152行目**: initialize_shared_array()で初期化

#### Step 3: データ分割とシリアライゼーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SharedArrays.jl | `stdlib/SharedArrays/src/SharedArrays.jl` | **406-422行目**: range_1dim()でワーカーごとのインデックス範囲を計算 |
| 3-2 | SharedArrays.jl | `stdlib/SharedArrays/src/SharedArrays.jl` | **443-472行目**: serialize()のカスタム実装。s, pidx, loc_subarr_1dフィールドを除外 |

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

```
SharedArray{T,N}(dims; pids, init)
    |
    +-- shared_pids(pids)                       # プロセス解決
    |   +-- procs(myid())                       # ローカルホストのプロセス取得
    |   +-- check_same_host(pids)               # 同一ホスト検証
    |
    +-- shm_mmap_array(T, dims, seg_name, mode) # 共有メモリ作成
    |   +-- shm_open(seg_name, mode, perms)     # POSIX shm_open
    |   +-- ftruncate(fd, size)                 # サイズ設定
    |   +-- mmap(io, Array{T,N}, dims, 0)       # メモリマッピング
    |
    +-- remotecall(func_mapshmem, p)            # ワーカーへ配布
    |
    +-- shm_unlink(seg_name)                    # セグメント名削除
    |
    +-- initialize_shared_array(S, ...)
        +-- init_loc_flds(S)                    # ローカルフィールド初期化
        +-- remotecall_wait(init, p, S)         # init関数実行
        +-- finalizer(finalize_refs, S)         # ファイナライザ登録
```

### データフロー図

```
[入力]               [処理]                          [出力]

型+次元+pids   ───▶  SharedArray コンストラクタ ───▶  SharedArray{T,N}
                     shm_open + mmap                   (共有メモリ配列)

SharedArray    ───▶  getindex/setindex!          ───▶  値の読み書き
                     内部のsフィールドに委譲            (ローカルArray経由)

SharedArray    ───▶  fill!/rand!/map!            ───▶  分散実行結果
                     @sync + remotecall_wait           (全ワーカーで並列)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SharedArrays.jl | `stdlib/SharedArrays/src/SharedArrays.jl` | ソース | 全実装を含む単一ファイル。SharedArray型、コンストラクタ、操作、シリアライゼーション |
| Project.toml | `stdlib/SharedArrays/Project.toml` | 設定 | パッケージ依存関係（Mmap, Distributed, Random, Serialization） |
| runtests.jl | `stdlib/SharedArrays/test/runtests.jl` | テスト | ユニットテスト |
