# スレッドセーフタイプ

> Understand Unity's custom thread-safe type, NativeContainer.

ジョブシステムは、[Burst コンパイラー](https://docs.unity3d.com/Packages/com.unity.burst@latest/) と併用するのが最も効果的です。Burst はマネージオブジェクトをサポートしていないので、ジョブのデータにアクセスするにはアンマネージタイプを使う必要があるためです。これには [blittable 型](https://learn.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types) を使うか、Unity のビルトインの [`NativeContainer`](/engine/6000.0/script-reference/unity-collections-low-level-unsafe/native-container-attribute.md) オブジェクトを使用できます。これらは、ネイティブメモリのためのスレッドセーフな C# ラッパーです。`NativeContainer` オブジェクトはジョブがコピーで作業するのではなく、[メインスレッド](/engine/6000.0/manual/scripting/optimization/job-system/overview.md#multithreading) と共有されるデータにアクセスすることを可能にします。

## NativeContainer の型

`Unity.Collections` 名前空間には、以下のビルトイン `NativeContainer` オブジェクトがあります。

* [`NativeArray`](/engine/6000.0/script-reference/unity-collections/native-array-1.md): マネージコードにネイティブメモリのバッファを公開するアンマネージ配列
* [`NativeSlice`](/engine/6000.0/script-reference/unity-collections/native-slice-1.md): `NativeArray` の特定の位置から特定の長さのサブセットを取得します。

**注意**[Collections パッケージ](https://docs.unity3d.com/Packages/com.unity.collections@latest/) には、追加の `NativeContainer` が含まれています。追加の型の完全なリストについては、Collections ドキュメントの [Collection 型](https://docs.unity3d.com/Packages/com.unity.collections@latest/index.html?subfolder=/manual/collection-types.html) を参照してください。

## 読み書きアクセス

デフォルトでは、`NativeContainer` インスタンスへアクセスできるジョブは、読み取りと書き込みの両方のアクセスが可能です。この設定はパフォーマンスを遅くする可能性があります。これは、ジョブシステムでは、`NativeContainer` インスタンスへの書き込みアクセス権を持つジョブを、そのインスタンスへの書き込みアクセス権を持つ他のジョブと同時にスケジュールすることができないためです。

しかし、ジョブが `NativeContainer` インスタンスに書き込む必要がない場合は、以下のように `NativeContainer` に `[ReadOnly]` 属性を設定することができます。

```lang-cs
[ReadOnly]
public NativeArray<int> input;
```

上の例では、読み取り専用アクセス権を持つジョブと、同様に最初の `NativeArray` への読み取り専用アクセス権を持つその他のジョブを同時に実行することができます。

## メモリ割り当て

`NativeContainer `インスタンスを作成するときに、必要なメモリ割り当てタイプを指定する必要があります。使用する割り当てタイプは、ネイティブコンテナを使用可能な状態にしておく時間によって決まります。これにより、各状況で最高のパフォーマンスが得られるように割り当てを調整できます。

`NativeContainer` メモリ割り当てと解放には 3 つの [Allocator](/engine/6000.0/script-reference/unity-collections/allocator.md) タイプがあります。`NativeContainer` インスタンスをインスタンス化するときに適切なものを指定する必要があります。

* `Allocator.Temp`: 最も高速な割り当てが可能です。生存期間が 1 フレーム以下の割り当てに使ってください。ただし、`Temp` を使って、ジョブのメンバーフィールドに保管されている `NativeContainer` インスタンスに割り当てを渡すことはできません。
* `Allocator.TempJob`: `Temp` よりもスピードの遅い割り当てですが、`Persistent` よりも高速です。これは、4 フレーム以内の生存期間のスレッドセーフな割り当てに使用します。**重要**:4 フレーム以内でこの割り当てタイプに `Dispose` を行わないと、コンソールはネイティブコードから生成された警告を出力します。ほとんどの小さなジョブはこの割り当てタイプを使用します。
* `Allocator.Persistent`: 最も遅い割り当てですが、好きなだけ長く、必要な場合は、アプリケーションの生存期間を通して使用できます。これは、[`malloc`](http://www.cplusplus.com/reference/cstdlib/malloc/) への直接呼び出しのためのラッパーです。長いジョブはこの NativeContainer 割り当てタイプを使用できます。パフォーマンスが重要な場合は `Persistent` を使用しないでください。

例:

```lang-cs
NativeArray<float> result = new NativeArray<float>(1, Allocator.TempJob);
```

**注意**上の例の数字 1 は、NativeArray のサイズを示しています。この場合、配列要素は 1 つだけです。理由は、result (結果) に 1 つのデータしか格納しないためです。

## NativeContainer と安全システム

[安全システム](/engine/6000.0/manual/scripting/optimization/job-system/overview.md#safety-system) はすべての `NativeContainer` インスタンスに組み込まれています。すべての `NativeContainer` インスタンスへの読み込みや書き込みを追跡し、その情報を使って `NativeContainer` の使用に一定のルールを適用し、複数のジョブやスレッドにまたがって決定論的な動作を行うようにします。

例えば、2 つの個々にスケジュールされたジョブが同じ `NativeArray` に書き込む場合、どちらのジョブが先に実行されるか予測できないため、これは安全ではありません。つまり、どちらのジョブがもう一方のジョブのデータを上書きするかわからないということです。安全システムは、2 番目のジョブがスケジュールされる際に、理由と問題を解決する方法を説明する明確なエラーメッセージとともに例外をスローします。

同じ `NativeContainer` インスタンスに書き込む 2 つのジョブをスケジュールする場合、[依存関係を持つジョブ](/engine/6000.0/manual/scripting/optimization/job-system/job-dependencies.md) をスケジュールできます。最初のジョブが `NativeContainer` に書き込み、実行が終了すると、次のジョブが同じ `NativeContainer` を安全に読み書きします。依存関係を導入することで、ジョブが常に一貫した順序で実行され、`NativeContainer` 内の結果のデータが決定論的であることが保証されます。

安全システムは、複数のジョブが同じデータを並行して読み取ることを可能にします。

これらの読み取りと書き込みの制限は、メインスレッドからデータにアクセスするときにも適用されます。例えば、NativeContainer に書き込むジョブが完了する前に NativeContainer のコンテンツを読み取ろうとすると、安全システムはエラーをスローします。同様に、NativeContainer への読み取りまたは書き込みを保留しているジョブがまだあるときに NativeContainer に書き込もうとすると、安全システムはエラーをスローします。

また、NativeContainer は [`ref return`](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/ref-returns) を実装していないため、`NativeContainer` のコンテンツを直接変更することはできません。例えば、`nativeArray[0]++;` は `var temp = nativeArray[0]; temp++;` と書くのと同じで、`nativeArray` の値は更新されません。

代わりに、インデックスのデータからローカルの一時的なコピーを作成し、そのコピーを変更して、それを元のデータに保存する必要があります。 例:

```lang-cs
MyStruct temp = myNativeArray[i];
temp.memberVariable = 0;
myNativeArray[i] = temp;
```

## 追加リソース

* [カスタム `NativeContainer` の実装](/engine/6000.0/manual/scripting/optimization/job-system/native-container/custom-nativecontainer.md)
