Unity 6.3
0 онлайн 67 гостей 3 в системе
Вход

NativeContainerAttribute

класс в Unity.Collections.LowLevel.Unsafe

Выполнено в:UnityEngine.CoreModule

Описание

Позволяет создать собственный настраиваемый контейнер.

Основные контейнеры позволяют создавать новые типы контейнеров, которые не выделяют никаких GC Вы также можете использовать собственные контейнеры в заданиях. Отладчик заданий убеждается, что все доступы к собственным контейнерам безопасны и бросает исключения, если какой-либо код содержит условия гонки или недетерминистическое поведение.

Нативные контейнеры должны встраивать AtomicSafetyHandle для обеспечения того, чтобы система отладки работ могла обнаружить любые возможные условия гонки, и отслеживание утечки происходит автоматически всякий раз, когда UnsafeUtility.MallocTracked называется.

Для создания собственного пользовательского контейнера используйте следующий пример кода. Следует добавить тестовое покрытие для всех сценариев, особенно для интеграции в задания, чтобы убедиться, что все условия гонки предотвращены. Если пользовательский контейнер реализован неправильно, он может выйти из строя Unity и не сделали оговорки [не сказали: «если Аллах пожелает»].

Также можно использовать пакет Collections для создания зарегистрированного пользовательского распределителя для выделения собственного пользовательского контейнера. Дополнительные сведения см. в документации Collections по [Условные распределители](https://docs.unity3d.com/Packages/com.unity.collections@latest/index.html?subfolder=/manual/allocator-custom-define.html).

using System.Diagnostics;
using System;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Collections;
using Unity.Burst;

// Marks our struct as a NativeContainer. // If ENABLE_UNITY_COLLECTIONS_CHECKS is enabled, // it is required that m_Safety with exactly this name. [NativeContainer] // The [NativeContainerSupportsMinMaxWriteRestriction] enables // a common jobification pattern where an IJobParallelFor is split into ranges // And the job is only allowed to access the index range being Executed by that worker thread. // Effectively limiting access of the array to the specific index passed into the Execute(int index) method // This attribute requires m_MinIndex & m_MaxIndex to exist. // and the container is expected to perform out of bounds checks against it. // m_MinIndex & m_MaxIndex will be set by the job scheduler before Execute is called on the worker thread. [NativeContainerSupportsMinMaxWriteRestriction] // It is recommended to always implement a Debugger proxy // to visualize the contents of the array in VisualStudio and other tools. [DebuggerDisplay("Length = {Length}")] [DebuggerTypeProxy(typeof(NativeCustomArrayDebugView<>))] public unsafe struct NativeCustomArray<T> : IDisposable where T : unmanaged { internal void* m_Buffer; internal int m_Length;

#if ENABLE_UNITY_COLLECTIONS_CHECKS internal int m_MinIndex; internal int m_MaxIndex; internal AtomicSafetyHandle m_Safety; internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<NativeCustomArray<T>>(); #endif

internal Allocator m_AllocatorLabel;

public NativeCustomArray(int length, Allocator allocator) { int totalSize = UnsafeUtility.SizeOf<T>() * length;

#if ENABLE_UNITY_COLLECTIONS_CHECKS // Native allocation is only valid for Temp, TempJob, Persistent or registered custom allocator if (allocator <= Allocator.None) throw new ArgumentException("Allocator must be Temp, TempJob, Persistent or registered custom allcoator", "allocator"); if (length < 0) throw new ArgumentOutOfRangeException("length", "Length must be >= 0"); if (!UnsafeUtility.IsBlittable<T>()) throw new ArgumentException(string.Format("{0} used in NativeCustomArray<{0}> must be blittable", typeof(T))); #endif

m_Buffer = AllocatorManager.Allocate(allocator, totalSize, UnsafeUtility.AlignOf<T>()); UnsafeUtility.MemClear(m_Buffer, totalSize);

m_Length = length; m_AllocatorLabel = allocator;

#if ENABLE_UNITY_COLLECTIONS_CHECKS m_MinIndex = 0; m_MaxIndex = length - 1; m_Safety = CollectionHelper.CreateSafetyHandle(allocator); CollectionHelper.SetStaticSafetyId<NativeCustomArray<T>>(ref m_Safety, ref s_staticSafetyId.Data); #endif }

public int Length { get { return m_Length; } }

public unsafe T this[int index] { get { #if ENABLE_UNITY_COLLECTIONS_CHECKS // If the container is currently not allowed to read from the buffer // then this will throw an exception. // This handles all cases, from already disposed containers // to safe multithreaded access. AtomicSafetyHandle.CheckReadAndThrow(m_Safety);

// Perform out of range checks based on // the NativeContainerSupportsMinMaxWriteRestriction policy if (index < m_MinIndex || index > m_MaxIndex) FailOutOfRangeError(index); #endif // Read the element from the allocated native memory return UnsafeUtility.ReadArrayElement<T>(m_Buffer, index); }

set { #if ENABLE_UNITY_COLLECTIONS_CHECKS // If the container is currently not allowed to write to the buffer // then this will throw an exception. // This handles all cases, from already disposed containers // to safe multithreaded access. AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);

// Perform out of range checks based on // the NativeContainerSupportsMinMaxWriteRestriction policy if (index < m_MinIndex || index > m_MaxIndex) FailOutOfRangeError(index); #endif // Writes value to the allocated native memory UnsafeUtility.WriteArrayElement(m_Buffer, index, value); } }

public T[] ToArray() { #if ENABLE_UNITY_COLLECTIONS_CHECKS AtomicSafetyHandle.CheckReadAndThrow(m_Safety); #endif

var array = new T[Length]; for (var i = 0; i < Length; i++) array[i] = UnsafeUtility.ReadArrayElement<T>(m_Buffer, i); return array; }

public bool IsCreated { get { return m_Buffer != null; } }

public void Dispose() { #if ENABLE_UNITY_COLLECTIONS_CHECKS CollectionHelper.DisposeSafetyHandle(ref m_Safety); #endif

AllocatorManager.Free(m_AllocatorLabel, m_Buffer); m_Buffer = null; m_Length = 0; }

#if ENABLE_UNITY_COLLECTIONS_CHECKS private void FailOutOfRangeError(int index) { if (index < Length && (m_MinIndex != 0 || m_MaxIndex != Length - 1)) throw new IndexOutOfRangeException(string.Format( "Index {0} is out of restricted IJobParallelFor range [{1}...{2}] in ReadWriteBuffer.\n" + "ReadWriteBuffers are restricted to only read & write the element at the job index. " + "You can use double buffering strategies to avoid race conditions due to " + "reading & writing in parallel to the same elements from a job.", index, m_MinIndex, m_MaxIndex));

throw new IndexOutOfRangeException(string.Format("Index {0} is out of range of '{1}' Length.", index, Length)); }

#endif }

// Visualizes the custom array in the C# debugger internal sealed class NativeCustomArrayDebugView<T> where T : unmanaged { private NativeCustomArray<T> m_Array;

public NativeCustomArrayDebugView(NativeCustomArray<T> array) { m_Array = array; }

public T[] Items { get { return m_Array.ToArray(); } } }