Version: 2023.1
言語: 日本語
カスタムネイティブコンテナの実装
カスタム NativeContainer の例

NativeContainer 構造体のコピー

NativeContainer は値型です。つまり、変数に代入されると、Unity は NativeContainer 構造体をコピーします。この構造体には、AtomicSafetyHandle など、ネイティブコンテナのデータが保存されている場所へのポインターが保存されますが、NativeContainer のコンテンツ全体をコピーするわけではありません。

このシナリオは、NativeContainer 構造体の複数のコピーが存在し、そのすべてが同じメモリ領域を参照し、すべてが同じ主要記録を参照する AtomicSafetyHandle オブジェクトを含む可能性があることを意味します。

NativeContainer オブジェクトのコピーの仕組み
NativeContainer オブジェクトのコピーの仕組み

上図は、同じ実在するコンテナを表す NativeArray 構造体の 3 つの異なるコピーを示しています。各コピーは保存された同じデータを指しており、元の NativeArray と同じ安全データを指しています。ただし、NativeArray の各コピーには、ジョブがそのコピーで実行可能なことを示す異なるフラグがあります。安全データへのポインターは、フラグとの組み合わせで、AtomicSafetyHandle を構成します。

バージョン番号

NativeContainer が破棄されると、NativeContainer 構造体のすべてのコピーは、元の NativeContainer が無効であることを認識します。元の NativeContainer の廃棄は、NativeContainer のデータを保持していたメモリブロックが解放されたということです。この状況で NativeContainer の各コピーに格納されているデータへのポインターは無効であり、これを使用するとアクセス違反を引き起こす可能性があります。

AtomicSafetyHandle は、NativeContainer インスタンスに対して無効となる主要記録も指します。ただし、安全システムは主要記録のメモリを解放しません。そのため、アクセス違反のリスクを回避できます。

代わりに、各記録にはバージョン番号が含まれます。バージョン番号のコピーは、そのレコードを参照する各 AtomicSafetyHandle 内に格納されます。NativeContainer が破棄されると、Unity は Release() を呼び出し、主要記録のバージョン番号を増加します。この後、この記録を他の NativeContainer インスタンスに再利用できます。

残存する各 AtomicSafetyHandle は、NativeContainer が破棄されたかどうかをテストするために、保存されているバージョン番号と主要記録のバージョン番号を比較します。Unity はこのテストを CheckReadAndThrowCheckWriteAndThrow などのメソッドの呼び出しの一部として自動的に実行します。

動的ネイティブコンテナの静的ビュー

動的なネイティブコンテナとは、NativeList<T>(Collections パッケージで利用可能) など、要素を加え続けることができる可変のサイズを持つコンテナのことです。 のような静的ネイティブコンテナとは対照的です。 これは、NativeArray<T> のようにサイズが変更不可能で固定されているものとは対照的です。

動的なネイティブコンテナを使用する場合、ビューと呼ばれる別のイン ターフェースを使用してそのデータに直接アクセスすることもできます。ビューを使用すると、NativeContainer オブジェクトのデータをコピーしたり所有権を取得したりすることなく、エイリアスを作成できます。ビューの例としては、列挙オブジェクトがあり、これを使用してネイティブコンテナの要素ごとにデータにアクセスできます。また、 NativeList<T>.AsArray などのメソッドは、NativeListNativeArray のように扱うことができます。

動的なネイティブコンテナのサイズが変更される場合、ビューは通常スレッドセーフではありません。これは、ネイティブコンテナのサイズが変更されると、Unity がメモリ内のデータの格納場所を変更するため、ビューが格納するポインターが無効になるためです。

補助バージョン番号

動的ネイティブコンテナのサイズが変更される場合に対応するため、安全システムには AtomicSafetyHandle に補助バージョン番号が含まれています。このメカニズムはバージョンメカニズムに似ていますが、主要記録に格納された 2 番目のバージョン番号を使用し、1 番目のバージョン番号とは独立して増加されます。

補助バージョン番号を使用するには UseSecondaryVersion を使用して、NativeContainer に格納されているデータにビューを構成します。ネイティブコンテナのサイズを変更する操作や、既存のビューを無効にする操作には CheckWriteAndThrow の代わりに CheckWriteAndBumpSecondaryVersion使用します。また、NativeContainerに [SetBumpSecondaryVersionOnScheduleWrite`](../ScriptReference/Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.SetBumpSecondaryVersionOnScheduleWrite.html) を設定し、ネイティブコンテナに書き込むジョブがスケジュールされるたびにビューを自動的に無効にする必要があります。

ビューを作成し、そこに AtomicSafetyHandle をコピーする際に、CheckGetSecondaryDataPointerAndThrow を使用して、ネイティブコンテナのメモリへのポインターをビューにコピーしても安全であることを確認します。

特殊フォルダー

一時的なネイティブコンテナで作業するときに使える特別なハンドルが 2 つあります。

  • GetTempMemoryHandle: Allocator.Temp と共に割り当てられたネイティブコンテナで使用できる AtomicSafetyHandle を返します。Unity は、現在の一時メモリスコープが終了すると、このハンドルを自動的に無効にします。そのため、自分で解除する必要はありません。特定の AtomicSafetyHandleGetTempMemoryHandle によって返されたハンドルであるかどうかをテストするには、IsTempMemoryHandle を使用します。
  • GetTempUnsafePtrSliceHandle: 安全でないメモリで保持された一時的なネイティブコンテナに使用できるグローバルハンドルを返します。例えば、スタックメモリから構築された NativeSlice などです。このハンドルを使用するコンテナをジョブに渡すことはできません。
カスタムネイティブコンテナの実装
カスタム NativeContainer の例