(Russian translation from English by Maxim Voloshin)

Unity 2018.3 принес нам еще больше потокобезопасного API, которое мы можем использовать с Job System. Сегодня мы рассмотрим способ поиска такого API, чтобы точно знать что использовать безопасно, а что нет.

Предыдущие статьи (2018.1, 2018.2) предоставляют списки потокобезопасного API, но те списки были получены в результате декомпиляции всех DLL движка Unity, последующего использования grep, чтобы найти [ThreadSafe] и IsThreadSafe = true и ручного форматирования результатов поиска в статью. Это очень долгий, утомительный и подверженный ошибкам процесс, который может быть улучшен.

Итак, теперь у нас есть маленький скрипт для редактора Unity, который сгенерирует список для нас. Вот, что он делает:

  1. В файлах установленного редактора Unity, находит все .dll файлы в папке Managed
  2. Открывает их как сборку
  3. Сканирует все их методы и свойства
  4. Проверяет присутствует ли атрибут [NativeMethod]
  5. Вызывает NativeMethodAttribute.IsThreadSafe
  6. Выводит все совпадения в Debug.Log и буфер обмена

Сейчас этот скрипт работает только в macOS, но может быть легко адаптирован для поддержки Windows или Linux сменой managedDirPath:

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEditor;
 
public static class JobSafeMenuItem
{
    [MenuItem("Help/List Job Safe APIs")]
    private static void JobSafe()
    {
#if !UNITY_EDITOR_OSX
        throw new Exception("Only macOS is supported at this time");
#endif
        string managedDirPath = Path.Combine(
            Path.Combine(
                EditorApplication.applicationPath,
                "Contents"),
            "Managed");
        Type nativeMethodAttribute = Assembly.LoadFile(
            Path.Combine(
                Path.Combine(
                    managedDirPath,
                    "UnityEngine"),
                "UnityEngine.SharedInternalsModule.dll"))
            .GetType("UnityEngine.Bindings.NativeMethodAttribute");
        string[] paths = Directory.GetFiles(
            managedDirPath,
            "*.dll",
            SearchOption.AllDirectories);
        var methodsByType = new Dictionary<Type, List<string>>(512);
        object[] emptyParameters = { };
        void AddIfThreadSafe(Type type, Attribute attribute, string method)
        {
            if (nativeMethodAttribute.IsInstanceOfType(attribute)
                && (bool)nativeMethodAttribute
                    .GetProperty("IsThreadSafe")
                    .GetGetMethod()
                    .Invoke(attribute, emptyParameters))
            {
                List<string> list;
                if (!methodsByType.TryGetValue(type, out list))
                {
                    list = new List<string>(32);
                    methodsByType[type] = list;
                }
                list.Add(method);
            }
        }
        BindingFlags allFlags =
            BindingFlags.NonPublic
            | BindingFlags.Static
            | BindingFlags.Instance;
        foreach (var path in paths)
        {
            Assembly assembly = Assembly.LoadFile(path);
            foreach (Type type in assembly.GetTypes())
            {
                foreach (MethodInfo meth in type.GetMethods(allFlags))
                {
                    foreach (Attribute attribute in meth.GetCustomAttributes())
                    {
                        AddIfThreadSafe(type, attribute, meth.ToString());
                    }
                }
                foreach (PropertyInfo prop in type.GetProperties(allFlags))
                {
                    foreach (Attribute attribute in prop.GetCustomAttributes())
                    {
                        AddIfThreadSafe(type, attribute, prop.ToString());
                    }
                }
            }
        }
 
        StringBuilder builder = new StringBuilder(1024 * 10);
        var sortedMethodsByType = new List<KeyValuePair<Type, List<string>>>(
            methodsByType);
        sortedMethodsByType.Sort((a, b) => a.Key.Name.CompareTo(b.Key.Name));
        foreach (var pair in sortedMethodsByType)
        {
            pair.Value.Sort();
            foreach (string method in pair.Value)
            {
                builder.Append(pair.Key.Name);
                builder.Append(":    ");
                builder.AppendLine(method);
            }
        }
        Debug.Log(builder.ToString());
        EditorGUIUtility.systemCopyBuffer = builder.ToString();
    }
}

Его очень легко использовать, просто скопируйте код в .cs файл и положите его в папку Editor проекта. Затем кликните Help > List Job Safe APIs, чтобы запустить скрипт. Через несколько секунд список будет выведен в лог на панели Console. Этот лог довольно длинный и, вероятно, список не влезет в лог полностью, но он также копируется в буфер обмена. Вставьте его в текстовый редактор, чтобы увидеть полностью.

Я запустил это в Unity 2018.1.3f2 и получил следующее:

ActiveEditorTracker:    Void Internal_Create(UnityEditor.ActiveEditorTracker)
ActiveEditorTracker:    Void Internal_Dispose(UnityEditor.ActiveEditorTracker)
Analytics:    Boolean IsInitialized()
Analytics:    Boolean QueueEvent(System.String, System.Object, Int32, System.String)
Analytics:    UnityEngine.Analytics.AnalyticsResult SendEventWithLimit(System.String, System.Object, Int32, System.String)
AnimationCurve:    Int32 AddKey_Internal(UnityEngine.Keyframe)
AnimationCurve:    IntPtr Internal_Create(UnityEngine.Keyframe[])
AnimationCurve:    UnityEngine.Keyframe GetKey(Int32)
AnimationCurve:    UnityEngine.Keyframe[] GetKeys()
AnimationCurve:    Void Internal_Destroy(IntPtr)
AnimationCurve:    Void SetKeys(UnityEngine.Keyframe[])
AnimationHumanStream:    Single GetFootHeight(Boolean)
AnimationHumanStream:    Single GetHumanScale()
AnimationHumanStream:    Single InternalGetGoalWeightPosition(UnityEngine.AvatarIKGoal)
AnimationHumanStream:    Single InternalGetGoalWeightRotation(UnityEngine.AvatarIKGoal)
AnimationHumanStream:    Single InternalGetHintWeightPosition(UnityEngine.AvatarIKHint)
AnimationHumanStream:    Single InternalGetMuscle(UnityEngine.Experimental.Animations.MuscleHandle)
AnimationHumanStream:    UnityEngine.Quaternion InternalGetBodyLocalRotation()
AnimationHumanStream:    UnityEngine.Quaternion InternalGetBodyRotation()
AnimationHumanStream:    UnityEngine.Quaternion InternalGetGoalLocalRotation(UnityEngine.AvatarIKGoal)
AnimationHumanStream:    UnityEngine.Quaternion InternalGetGoalRotation(UnityEngine.AvatarIKGoal)
AnimationHumanStream:    UnityEngine.Quaternion InternalGetGoalRotationFromPose(UnityEngine.AvatarIKGoal)
AnimationHumanStream:    UnityEngine.Vector3 GetLeftFootVelocity()
AnimationHumanStream:    UnityEngine.Vector3 GetRightFootVelocity()
AnimationHumanStream:    UnityEngine.Vector3 InternalGetBodyLocalPosition()
AnimationHumanStream:    UnityEngine.Vector3 InternalGetBodyPosition()
AnimationHumanStream:    UnityEngine.Vector3 InternalGetGoalLocalPosition(UnityEngine.AvatarIKGoal)
AnimationHumanStream:    UnityEngine.Vector3 InternalGetGoalPosition(UnityEngine.AvatarIKGoal)
AnimationHumanStream:    UnityEngine.Vector3 InternalGetGoalPositionFromPose(UnityEngine.AvatarIKGoal)
AnimationHumanStream:    UnityEngine.Vector3 InternalGetHintPosition(UnityEngine.AvatarIKHint)
AnimationHumanStream:    Void InternalResetToStancePose()
AnimationHumanStream:    Void InternalSetBodyLocalPosition(UnityEngine.Vector3)
AnimationHumanStream:    Void InternalSetBodyLocalRotation(UnityEngine.Quaternion)
AnimationHumanStream:    Void InternalSetBodyPosition(UnityEngine.Vector3)
AnimationHumanStream:    Void InternalSetBodyRotation(UnityEngine.Quaternion)
AnimationHumanStream:    Void InternalSetGoalLocalPosition(UnityEngine.AvatarIKGoal, UnityEngine.Vector3)
AnimationHumanStream:    Void InternalSetGoalLocalRotation(UnityEngine.AvatarIKGoal, UnityEngine.Quaternion)
AnimationHumanStream:    Void InternalSetGoalPosition(UnityEngine.AvatarIKGoal, UnityEngine.Vector3)
AnimationHumanStream:    Void InternalSetGoalRotation(UnityEngine.AvatarIKGoal, UnityEngine.Quaternion)
AnimationHumanStream:    Void InternalSetGoalWeightPosition(UnityEngine.AvatarIKGoal, Single)
AnimationHumanStream:    Void InternalSetGoalWeightRotation(UnityEngine.AvatarIKGoal, Single)
AnimationHumanStream:    Void InternalSetHintPosition(UnityEngine.AvatarIKHint, UnityEngine.Vector3)
AnimationHumanStream:    Void InternalSetHintWeightPosition(UnityEngine.AvatarIKHint, Single)
AnimationHumanStream:    Void InternalSetLookAtBodyWeight(Single)
AnimationHumanStream:    Void InternalSetLookAtClampWeight(Single)
AnimationHumanStream:    Void InternalSetLookAtEyesWeight(Single)
AnimationHumanStream:    Void InternalSetLookAtHeadWeight(Single)
AnimationHumanStream:    Void InternalSetLookAtPosition(UnityEngine.Vector3)
AnimationHumanStream:    Void InternalSetMuscle(UnityEngine.Experimental.Animations.MuscleHandle, Single)
AnimationHumanStream:    Void InternalSolveIK()
AnimationStream:    Boolean GetIsHumanStream()
AnimationStream:    Int32 GetInputStreamCount()
AnimationStream:    Single GetDeltaTime()
AnimationStream:    UnityEngine.Experimental.Animations.AnimationHumanStream GetHumanStream()
AnimationStream:    UnityEngine.Experimental.Animations.AnimationStream InternalGetInputStream(Int32)
AnimationStream:    UnityEngine.Quaternion GetRootMotionRotation()
AnimationStream:    UnityEngine.Vector3 GetAngularVelocity()
AnimationStream:    UnityEngine.Vector3 GetRootMotionPosition()
AnimationStream:    UnityEngine.Vector3 GetVelocity()
AnimationStream:    Void InternalReadSceneTransforms()
AnimationStream:    Void InternalWriteSceneTransforms()
AnimationStream:    Void SetAngularVelocity(UnityEngine.Vector3)
AnimationStream:    Void SetVelocity(UnityEngine.Vector3)
AnimatorControllerPlayable:    Int32 StringToHash(System.String)
Asset:    IntPtr Create(System.String)
Asset:    States GetState(IntPtr)
Asset:    Void Destroy(IntPtr)
AssetBundle:    UnityEngine.Object returnMainAsset(UnityEngine.AssetBundle)
AsyncOperation:    Void InternalDestroy(IntPtr)
AsyncReadManager:    Unity.IO.LowLevel.Unsafe.ReadHandle ReadInternal(System.String, Void*, UInt32)
AtomicSafetyHandle:    Void CheckReadAndThrowNoEarlyOut(Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle)
AtomicSafetyHandle:    Void CheckWriteAndThrowNoEarlyOut(Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle)
AudioSampleProvider:    Boolean InternalGetEnableSampleFramesAvailableEvents(UInt32)
AudioSampleProvider:    Boolean InternalGetEnableSilencePadding(UInt32)
AudioSampleProvider:    Boolean InternalIsValid(UInt32)
AudioSampleProvider:    IntPtr InternalGetConsumeSampleFramesNativeFunctionPtr()
AudioSampleProvider:    UInt32 InternalGetAvailableSampleFrameCount(UInt32)
AudioSampleProvider:    UInt32 InternalGetFreeSampleFrameCount(UInt32)
AudioSampleProvider:    UInt32 InternalGetFreeSampleFrameCountLowThreshold(UInt32)
AudioSampleProvider:    UInt32 InternalGetMaxSampleFrameCount(UInt32)
AudioSampleProvider:    Void InternalSetEnableSampleFramesAvailableEvents(UInt32, Boolean)
AudioSampleProvider:    Void InternalSetEnableSilencePadding(UInt32, Boolean)
AudioSampleProvider:    Void InternalSetFreeSampleFrameCountLowThreshold(UInt32, UInt32)
AudioSampleProvider:    Void InternalSetScriptingPtr(UInt32, UnityEngine.Experimental.Audio.AudioSampleProvider)
Bounds:    Boolean IntersectRayAABB(UnityEngine.Ray, UnityEngine.Bounds, Single ByRef)
BuildPipeline:    Boolean LicenseCheck(UnityEditor.BuildTarget)
BuildPipeline:    System.String GetBuildTargetName(UnityEditor.BuildTarget)
BuildPipeline:    System.String GetBuildToolsDirectory(UnityEditor.BuildTarget)
BuildPipeline:    System.String GetEditorTargetName()
BuildPipeline:    System.String GetPlaybackEngineDirectory(UnityEditor.BuildTargetGroup, UnityEditor.BuildTarget, UnityEditor.BuildOptions)
BuildPipeline:    System.String GetPlaybackEngineExtensionDirectory(UnityEditor.BuildTargetGroup, UnityEditor.BuildTarget, UnityEditor.BuildOptions)
BuildReferenceMap:    IntPtr Internal_Create()
BuildReferenceMap:    Void Internal_Destroy(IntPtr)
BuildUsageCache:    IntPtr Internal_Create()
BuildUsageCache:    Void Internal_Destroy(IntPtr)
BuildUsageTagSet:    IntPtr Internal_Create()
BuildUsageTagSet:    Void Internal_Destroy(IntPtr)
CertificateHandler:    Void Release()
ChangeSet:    IntPtr Create()
ChangeSet:    IntPtr CreateFromCopy(UnityEditor.VersionControl.ChangeSet)
ChangeSet:    IntPtr CreateFromString(System.String)
ChangeSet:    IntPtr CreateFromStringString(System.String, System.String)
ChangeSet:    Void Destroy(IntPtr)
Collab:    UnityEditor.Collaboration.Change[] GetSelectedChangesInternal()
Collab:    Void SetChangesToPublishInternal(UnityEditor.Collaboration.ChangeItem[])
CommandBuffer:    Void ReleaseBuffer()
ComputeBuffer:    Int32 GetLineNumber()
ComputeBuffer:    System.String GetFileName()
ConfigField:    Void Destroy(IntPtr)
ConnectionConfigInternal:    Void InternalDestroy(IntPtr)
ConnectionSimulatorConfigInternal:    Void InternalDestroy(IntPtr)
Coroutine:    Void ReleaseCoroutine(IntPtr)
CrashReport:    Boolean RemoveReport(System.String)
CrashReport:    System.String GetReportData(System.String, Double ByRef)
CrashReport:    System.String[] GetReports()
CullingGroup:    Void FinalizerFailure()
CustomEventData:    Void Internal_Destroy(IntPtr)
CustomSampler:    IntPtr CreateInternal(System.String)
CustomSampler:    Void BeginWithObject(UnityEngine.Object)
Device:    Void SettvOSNoBackupFlag(System.String)
Device:    Void tvOSResetNoBackupFlag(System.String)
DictationRecognizer:    Void DestroyThreaded(IntPtr)
DownloadHandler:    Void Release()
Event:    IntPtr Internal_Copy(IntPtr)
Event:    IntPtr Internal_Create(Int32)
Event:    Void CopyFromPtr(IntPtr)
Event:    Void Internal_Destroy(IntPtr)
FontEngine:    Boolean TryAddGlyphsToTexture_Internal(UInt32[], Int32, UnityEngine.TextCore.LowLevel.GlyphPackingMode, UnityEngine.TextCore.GlyphRect[], Int32 ByRef, UnityEngine.TextCore.GlyphRect[], Int32 ByRef, UnityEngine.TextCore.LowLevel.GlyphRenderMode, UnityEngine.Texture2D, UnityEngine.TextCore.LowLevel.GlyphMarshallingStruct[], Int32 ByRef)
FontEngine:    Boolean TryAddGlyphToTexture_Internal(UInt32, Int32, UnityEngine.TextCore.LowLevel.GlyphPackingMode, UnityEngine.TextCore.GlyphRect[], Int32 ByRef, UnityEngine.TextCore.GlyphRect[], Int32 ByRef, UnityEngine.TextCore.LowLevel.GlyphRenderMode, UnityEngine.Texture2D, UnityEngine.TextCore.LowLevel.GlyphMarshallingStruct ByRef)
FontEngine:    Boolean TryGetGlyphWithIndexValue_Internal(UInt32, UnityEngine.TextCore.LowLevel.GlyphLoadFlags, UnityEngine.TextCore.LowLevel.GlyphMarshallingStruct ByRef)
FontEngine:    Boolean TryGetGlyphWithUnicodeValue_Internal(UInt32, UnityEngine.TextCore.LowLevel.GlyphLoadFlags, UnityEngine.TextCore.LowLevel.GlyphMarshallingStruct ByRef)
FontEngine:    Boolean TryPackGlyphInAtlas_Internal(UnityEngine.TextCore.LowLevel.GlyphMarshallingStruct ByRef, Int32, UnityEngine.TextCore.LowLevel.GlyphPackingMode, UnityEngine.TextCore.LowLevel.GlyphRenderMode, Int32, Int32, UnityEngine.TextCore.GlyphRect[], Int32 ByRef, UnityEngine.TextCore.GlyphRect[], Int32 ByRef)
FontEngine:    Boolean TryPackGlyphsInAtlas_Internal(UnityEngine.TextCore.LowLevel.GlyphMarshallingStruct[], Int32 ByRef, UnityEngine.TextCore.LowLevel.GlyphMarshallingStruct[], Int32 ByRef, Int32, UnityEngine.TextCore.LowLevel.GlyphPackingMode, UnityEngine.TextCore.LowLevel.GlyphRenderMode, Int32, Int32, UnityEngine.TextCore.GlyphRect[], Int32 ByRef, UnityEngine.TextCore.GlyphRect[], Int32 ByRef)
FontEngine:    Int32 GetFaceInfo_Internal(UnityEngine.TextCore.FaceInfo ByRef)
FontEngine:    Int32 LoadGlyph_Internal(UInt32, UnityEngine.TextCore.LowLevel.GlyphLoadFlags)
FontEngine:    Int32 RenderGlyphsToSharedTexture_Internal(UnityEngine.TextCore.LowLevel.GlyphMarshallingStruct[], Int32, Int32, UnityEngine.TextCore.LowLevel.GlyphRenderMode)
FontEngine:    Int32 RenderGlyphsToTextureBuffer_Internal(UnityEngine.TextCore.LowLevel.GlyphMarshallingStruct[], Int32, Int32, UnityEngine.TextCore.LowLevel.GlyphRenderMode, Byte[], Int32, Int32)
FontEngine:    Int32 SetFaceSize_Internal(Int32)
FontEngine:    UInt32 GetGlyphIndex(UInt32)
FontEngine:    Void ReleaseSharedTexture()
FrameDataView:    IntPtr Internal_Create(UnityEditorInternal.Profiling.ProfilerViewType, Int32, Int32, UnityEditorInternal.Profiling.ProfilerColumn, Boolean, UnityEditorInternal.Profiling.FrameViewFilteringModes)
FrameDataView:    Void Internal_Destroy(IntPtr)
GcLeaderboard:    Void GcLeaderboard_Dispose(IntPtr)
GlobalConfigInternal:    Void InternalDestroy(IntPtr)
Gradient:    Boolean Internal_Equals(IntPtr)
Gradient:    IntPtr Init()
Gradient:    Void Cleanup()
GUIStyle:    IntPtr GetStyleStatePtr(Int32)
GUIStyle:    IntPtr Internal_Copy(UnityEngine.GUIStyle, UnityEngine.GUIStyle)
GUIStyle:    IntPtr Internal_Create(UnityEngine.GUIStyle)
GUIStyle:    Void Internal_Destroy(IntPtr)
GUIStyleState:    IntPtr Init()
GUIStyleState:    Void Cleanup()
HostTopologyInternal:    Void InternalDestroy(IntPtr)
InternalEditorUtility:    Boolean HasUFSTLicense()
JsonUtility:    System.Object FromJsonInternal(System.String, System.Object, System.Type)
JsonUtility:    System.Object FromJsonInternal(System.String, System.Object, System.Type)
JsonUtility:    System.String ToJsonInternal(System.Object, Boolean)
JsonUtility:    System.String ToJsonInternal(System.Object, Boolean)
LineUtility:    Void GeneratePointsToKeep2D(System.Object, Single, System.Object)
LineUtility:    Void GeneratePointsToKeep3D(System.Object, Single, System.Object)
LineUtility:    Void GenerateSimplifiedPoints2D(System.Object, Single, System.Object)
LineUtility:    Void GenerateSimplifiedPoints3D(System.Object, Single, System.Object)
MaterialPropertyBlock:    Void DestroyImpl(IntPtr)
Matrix4x4:    Boolean IsIdentity()
Matrix4x4:    Single GetDeterminant()
Matrix4x4:    UnityEngine.FrustumPlanes DecomposeProjection()
Matrix4x4:    UnityEngine.Quaternion GetRotation()
Matrix4x4:    UnityEngine.Vector3 GetLossyScale()
Message:    Void Destroy(IntPtr)
MonoBehaviour:    Void ConstructorCheck(UnityEngine.Object)
Native:    Void YGConfigFreeInternal(IntPtr)
Native:    Void YGNodeFreeInternal(IntPtr)
NativeFormatImporterUtility:    System.String Internal_GetExtensionForNativeAsset(UnityEngine.Object)
NativeFormatImporterUtility:    System.Type Internal_GetNativeTypeForExtension(System.String, Boolean ByRef)
NavMeshQuery:    Boolean GetPortalPoints(IntPtr, UnityEngine.Experimental.AI.PolygonId, UnityEngine.Experimental.AI.PolygonId, UnityEngine.Vector3 ByRef, UnityEngine.Vector3 ByRef)
NavMeshQuery:    Boolean HasNodePool(IntPtr)
NavMeshQuery:    Boolean IsPositionInPolygon(IntPtr, UnityEngine.Vector3, UnityEngine.Experimental.AI.PolygonId)
NavMeshQuery:    Boolean IsValidPolygon(IntPtr, UnityEngine.Experimental.AI.PolygonId)
NavMeshQuery:    Int32 GetAgentTypeIdForPolygon(IntPtr, UnityEngine.Experimental.AI.PolygonId)
NavMeshQuery:    Int32 GetPathResult(IntPtr, Void*, Int32)
NavMeshQuery:    UnityEngine.Experimental.AI.NavMeshLocation MapLocation(IntPtr, UnityEngine.Vector3, UnityEngine.Vector3, Int32, Int32)
NavMeshQuery:    UnityEngine.Experimental.AI.NavMeshLocation MoveLocation(IntPtr, UnityEngine.Experimental.AI.NavMeshLocation, UnityEngine.Vector3, Int32)
NavMeshQuery:    UnityEngine.Experimental.AI.NavMeshPolyTypes GetPolygonType(IntPtr, UnityEngine.Experimental.AI.PolygonId)
NavMeshQuery:    UnityEngine.Experimental.AI.PathQueryStatus BeginFindPath(IntPtr, UnityEngine.Experimental.AI.NavMeshLocation, UnityEngine.Experimental.AI.NavMeshLocation, Int32, Void*)
NavMeshQuery:    UnityEngine.Experimental.AI.PathQueryStatus EndFindPath(IntPtr, Int32 ByRef)
NavMeshQuery:    UnityEngine.Experimental.AI.PathQueryStatus GetClosestPointOnPoly(IntPtr, UnityEngine.Experimental.AI.PolygonId, UnityEngine.Vector3, UnityEngine.Vector3 ByRef)
NavMeshQuery:    UnityEngine.Experimental.AI.PathQueryStatus Raycast(IntPtr, UnityEngine.Experimental.AI.NavMeshLocation, UnityEngine.Vector3, Int32, Void*, UnityEngine.AI.NavMeshHit ByRef, Void*, Int32 ByRef, Int32)
NavMeshQuery:    UnityEngine.Experimental.AI.PathQueryStatus UpdateFindPath(IntPtr, Int32, Int32 ByRef)
NavMeshQuery:    UnityEngine.Matrix4x4 PolygonLocalToWorldMatrix(IntPtr, UnityEngine.Experimental.AI.PolygonId)
NavMeshQuery:    UnityEngine.Matrix4x4 PolygonWorldToLocalMatrix(IntPtr, UnityEngine.Experimental.AI.PolygonId)
NavMeshQuery:    Void MoveLocations(IntPtr, Void*, Void*, Void*, Int32)
NavMeshQuery:    Void MoveLocationsInSameAreas(IntPtr, Void*, Void*, Int32, Int32)
NotificationHelper:    Void DestroyLocal(IntPtr)
NotificationHelper:    Void DestroyRemote(IntPtr)
Object:    Boolean CurrentThreadIsMainThread()
Object:    Boolean DoesObjectWithInstanceIDExist(Int32)
Object:    Int32 GetOffsetOfInstanceIDInCPlusPlusObject()
ObjectGUIState:    Void Internal_Destroy(IntPtr)
OnDemandResourcesRequest:    Void DestroyFromScript(IntPtr)
PhraseRecognizer:    Void DestroyThreaded(IntPtr)
Ping:    Void Internal_Destroy(IntPtr)
Plugin:    Void Destroy(IntPtr)
Profiler:    Void BeginSampleImpl(System.String, UnityEngine.Object)
Profiler:    Void BeginThreadProfilingInternal(System.String, System.String)
ProfilerFrameDataIterator:    Void Internal_Destroy(IntPtr)
ProfilerMarker:    IntPtr Internal_Create(System.String, Unity.Profiling.MarkerFlags)
ProfilerMarker:    Void Internal_Begin(IntPtr)
ProfilerMarker:    Void Internal_BeginWithObject(IntPtr, UnityEngine.Object)
ProfilerMarker:    Void Internal_End(IntPtr)
ProfilerProperty:    Void Internal_Delete(IntPtr)
PropertySceneHandle:    Boolean GetBoolInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
PropertySceneHandle:    Boolean HasValidTransform(UnityEngine.Experimental.Animations.AnimationStream ByRef)
PropertySceneHandle:    Boolean IsBound(UnityEngine.Experimental.Animations.AnimationStream ByRef)
PropertySceneHandle:    Int32 GetIntInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
PropertySceneHandle:    Single GetFloatInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
PropertySceneHandle:    Void ResolveInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
PropertySceneHandle:    Void SetBoolInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, Boolean)
PropertySceneHandle:    Void SetFloatInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, Single)
PropertySceneHandle:    Void SetIntInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, Int32)
PropertyStreamHandle:    Boolean GetBoolInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
PropertyStreamHandle:    Int32 GetIntInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
PropertyStreamHandle:    Single GetFloatInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
PropertyStreamHandle:    Void ResolveInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
PropertyStreamHandle:    Void SetBoolInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, Boolean)
PropertyStreamHandle:    Void SetFloatInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, Single)
PropertyStreamHandle:    Void SetIntInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, Int32)
Quaternion:    UnityEngine.Quaternion Internal_FromEulerRad(UnityEngine.Vector3)
Quaternion:    UnityEngine.Vector3 Internal_ToEulerRad(UnityEngine.Quaternion)
Quaternion:    Void Internal_ToAxisAngleRad(UnityEngine.Quaternion, UnityEngine.Vector3 ByRef, Single ByRef)
ReadHandle:    Boolean IsReadHandleValid(Unity.IO.LowLevel.Unsafe.ReadHandle)
ReadHandle:    Unity.IO.LowLevel.Unsafe.ReadStatus GetReadStatus(Unity.IO.LowLevel.Unsafe.ReadHandle)
ReadHandle:    Unity.Jobs.JobHandle GetJobHandle(Unity.IO.LowLevel.Unsafe.ReadHandle)
ReadHandle:    Void ReleaseReadHandle(Unity.IO.LowLevel.Unsafe.ReadHandle)
Recorder:    Boolean IsEnabled()
Recorder:    Int32 GetSampleBlockCount()
Recorder:    Int64 GetElapsedNanoseconds()
Recorder:    Void DisposeNative(IntPtr)
Recorder:    Void SetEnabled(Boolean)
RemoteConfigSettings:    Void Internal_Destroy(IntPtr)
Sampler:    System.String GetSamplerName()
ScriptableObject:    Void CreateScriptableObject(UnityEngine.ScriptableObject)
SerializedObject:    Void Internal_Destroy(IntPtr)
SerializedObjectChangeTracker:    Void Internal_Destroy(IntPtr)
SerializedProperty:    Void Internal_Destroy(IntPtr)
Task:    Void Destroy(IntPtr)
TerrainData:    Int32 GetBoundaryValue(BoundaryValueType)
TextGenerator:    IntPtr Internal_Create()
TextGenerator:    Void Internal_Destroy(IntPtr)
TouchScreenKeyboard:    Void Internal_Destroy(IntPtr)
TransformAccess:    Void GetLocalPosition(UnityEngine.Jobs.TransformAccess ByRef, UnityEngine.Vector3 ByRef)
TransformAccess:    Void GetLocalRotation(UnityEngine.Jobs.TransformAccess ByRef, UnityEngine.Quaternion ByRef)
TransformAccess:    Void GetLocalScale(UnityEngine.Jobs.TransformAccess ByRef, UnityEngine.Vector3 ByRef)
TransformAccess:    Void GetPosition(UnityEngine.Jobs.TransformAccess ByRef, UnityEngine.Vector3 ByRef)
TransformAccess:    Void GetRotation(UnityEngine.Jobs.TransformAccess ByRef, UnityEngine.Quaternion ByRef)
TransformAccess:    Void SetLocalPosition(UnityEngine.Jobs.TransformAccess ByRef, UnityEngine.Vector3 ByRef)
TransformAccess:    Void SetLocalRotation(UnityEngine.Jobs.TransformAccess ByRef, UnityEngine.Quaternion ByRef)
TransformAccess:    Void SetLocalScale(UnityEngine.Jobs.TransformAccess ByRef, UnityEngine.Vector3 ByRef)
TransformAccess:    Void SetPosition(UnityEngine.Jobs.TransformAccess ByRef, UnityEngine.Vector3 ByRef)
TransformAccess:    Void SetRotation(UnityEngine.Jobs.TransformAccess ByRef, UnityEngine.Quaternion ByRef)
TransformAccessArray:    IntPtr GetSortedToUserIndex(IntPtr)
TransformAccessArray:    IntPtr GetSortedTransformAccess(IntPtr)
TransformSceneHandle:    Boolean HasValidTransform(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformSceneHandle:    UnityEngine.Quaternion GetLocalRotationInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformSceneHandle:    UnityEngine.Quaternion GetRotationInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformSceneHandle:    UnityEngine.Vector3 GetLocalPositionInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformSceneHandle:    UnityEngine.Vector3 GetLocalScaleInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformSceneHandle:    UnityEngine.Vector3 GetPositionInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformSceneHandle:    Void SetLocalPositionInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, UnityEngine.Vector3)
TransformSceneHandle:    Void SetLocalRotationInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, UnityEngine.Quaternion)
TransformSceneHandle:    Void SetLocalScaleInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, UnityEngine.Vector3)
TransformSceneHandle:    Void SetPositionInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, UnityEngine.Vector3)
TransformSceneHandle:    Void SetRotationInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, UnityEngine.Quaternion)
TransformStreamHandle:    UnityEngine.Quaternion GetLocalRotationInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformStreamHandle:    UnityEngine.Quaternion GetRotationInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformStreamHandle:    UnityEngine.Vector3 GetLocalPositionInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformStreamHandle:    UnityEngine.Vector3 GetLocalScaleInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformStreamHandle:    UnityEngine.Vector3 GetPositionInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformStreamHandle:    Void ResolveInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef)
TransformStreamHandle:    Void SetLocalPositionInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, UnityEngine.Vector3)
TransformStreamHandle:    Void SetLocalRotationInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, UnityEngine.Quaternion)
TransformStreamHandle:    Void SetLocalScaleInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, UnityEngine.Vector3)
TransformStreamHandle:    Void SetPositionInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, UnityEngine.Vector3)
TransformStreamHandle:    Void SetRotationInternal(UnityEngine.Experimental.Animations.AnimationStream ByRef, UnityEngine.Quaternion)
TypeDB:    IntPtr Internal_Create()
TypeDB:    Void Internal_Destroy(IntPtr)
UnityLogWriter:    Void WriteStringToUnityLogImpl(System.String)
UnityWebRequest:    System.String GetWebErrorString(UnityWebRequestError)
UnityWebRequest:    Void Release()
UnsafeUtility:    Int32 GetFieldOffsetInClass(System.Reflection.FieldInfo)
UnsafeUtility:    Int32 GetFieldOffsetInStruct(System.Reflection.FieldInfo)
UnsafeUtility:    Void LogError(System.String, System.String, Int32)
UnsafeUtility:    Void* PinSystemArrayAndGetAddress(System.Object, UInt64 ByRef)
UnsafeUtility:    Void* PinSystemObjectAndGetAddress(System.Object, UInt64 ByRef)
UploadHandler:    Void Release()
Vector3:    Void OrthoNormalize2(UnityEngine.Vector3 ByRef, UnityEngine.Vector3 ByRef)
Vector3:    Void OrthoNormalize3(UnityEngine.Vector3 ByRef, UnityEngine.Vector3 ByRef, UnityEngine.Vector3 ByRef)
VFXCPUBufferData:    Void Internal_Destroy(IntPtr)
VFXEventAttribute:    Void Internal_Destroy(IntPtr)
VFXSpawnerState:    Void Internal_Destroy(IntPtr)
WaveformStreamer:    Void Internal_WaveformStreamerDestroy(IntPtr)

Теперь у нас есть 301 потокобезопасная функция, но многие из них имеют модификаторы private или internal и должны вызываться косвенно через публичное API. В итоге, это просто расширение API с изначальных девяти методов и свойств, которые были в Unity 2018.2. Однако, Unity все чаще распространяет новое API с помощью системы пакетов, как ECS, на данный момент находящийся в состоянии превью. Для того, чтобы исследовать любые пакеты с помощью этого скрипта, просто добавьте в переменную paths путь до папки с нужными вам библиотеками.