包含此页的版本:
不含此页的版本:
本机容器是值类型,这意味着当它们被分配给变量时,Unity 会复制NativeContainer结构,其中包含指向本机容器数据存储位置的指针,包括其AtomicSafetyHandle.它不会复制NativeContainer.
这种情况意味着可能存在多个副本NativeContainer所有引用同一内存区域的结构,并且都包含AtomicSafetyHandle引用同一中心记录的对象。
上图显示了NativeArray结构,这些结构都代表同一个实际容器。每个副本都指向与原始副本相同的存储数据和相同的安全数据NativeArray.但是,每个副本的NativeArray具有不同的标志,指示允许作业对该副本执行的作。指向安全数据的指针与标志相结合,构成了AtomicSafetyHandle.
如果NativeContainer被处理后,所有副本NativeContainer结构必须识别原始的NativeContainer无效。处理原件NativeContainer表示用于保存数据的内存块NativeContainer已解除分配。在这种情况下,指向存储在NativeContainer无效,如果使用它,可能会导致访问冲突。
这AtomicSafetyHandle还指向一个中央记录,该记录对NativeContainer实例。但是,安全系统永远不会释放中央记录的内存,因此它避免了访问违规的风险。
相反,每条记录都包含一个版本号。版本号的副本存储在每个AtomicSafetyHandle引用该记录。当 NativeContainer 被处置时,Unity 会调用Release(),这将增加中央记录上的版本号。在此之后,该记录可以重复用于其他NativeContainer实例。
剩余的每个AtomicSafetyHandle将其存储的版本号与中央记录中的版本号进行比较,以测试NativeContainer已被处理。Unity 在调用CheckReadAndThrow和CheckWriteAndThrow.
动态本机容器是具有可变大小的容器,您可以继续向其添加元素,例如NativeList<T>(在 Collections 包中可用)。这与静态本机容器(如NativeArray<T>,它具有无法更改的固定大小。
使用动态原生容器时,还可以通过另一个接口(称为视图)直接访问其数据。视图允许您将NativeContainer对象的数据,而无需复制或获取数据的所有权。视图的示例包括枚举器对象,您可以使用这些对象逐个元素访问本机容器中的数据,以及NativeList<T>.AsArray,您可以使用它来治疗NativeList就好像它是NativeArray.
如果动态本机容器的大小发生变化,视图通常不是线程安全的。这是因为当本机容器的大小发生变化时,Unity 会重新定位内存中存储数据的位置,这会导致视图存储的任何指针都变得无效。
为了支持动态本机容器大小发生变化的情况,安全系统在AtomicSafetyHandle.此机制类似于版本控制机制,但使用存储在中央记录中的第二个版本号,该版本号可以独立于第一个版本号递增。
要使用辅助版本号,您可以使用UseSecondaryVersion将视图配置为存储在NativeContainer.对于更改本机容器大小或使现有视图无效的作,请使用CheckWriteAndBumpSecondaryVersion而不是CheckWriteAndThrow.您还需要设置SetBumpSecondaryVersionOnScheduleWrite在NativeContainer每当计划写入本机容器的作业时,都会自动使视图失效。
当您创建视图并复制AtomicSafetyHandle对它,使用CheckGetSecondaryDataPointerAndThrow以确认将指向本机容器内存的指针复制到视图中是否安全。
有两个特殊的句柄,在处理临时本机容器时可以使用它们:
GetTempMemoryHandle:返回AtomicSafetyHandle您可以在分配的本机容器中使用Allocator.Temp.当当前临时内存作用域退出时,Unity 会自动使此句柄失效,因此您无需自行释放它。要测试特定AtomicSafetyHandle是GetTempMemoryHandle用IsTempMemoryHandle.GetTempUnsafePtrSliceHandle:返回一个全局句柄,可用于由不安全内存支持的临时本机容器。例如,一个NativeSlice由堆栈内存构建。无法将使用此句柄的容器传递到作业中。