mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 01:44:35 +08:00
fix thread safety
This commit is contained in:
parent
effa02e660
commit
b4af20d2ea
@ -1,6 +1,6 @@
|
||||
using DCFApixels.DragonECS.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
@ -116,6 +116,8 @@ namespace DCFApixels.DragonECS
|
||||
public abstract class DebugService
|
||||
{
|
||||
private static DebugService _instance;
|
||||
private static object _lock = new object();
|
||||
|
||||
public static DebugService Instance
|
||||
{
|
||||
get
|
||||
@ -141,7 +143,7 @@ namespace DCFApixels.DragonECS
|
||||
public static Action<DebugService> OnServiceChanged = delegate { };
|
||||
|
||||
private IdDispenser _idDispenser = new IdDispenser(4, -1);
|
||||
private Dictionary<string, int> _nameIdTable = new Dictionary<string, int>();
|
||||
private ConcurrentDictionary<string, int> _nameIdTable = new ConcurrentDictionary<string, int>();
|
||||
public abstract void Print(string tag, object v);
|
||||
public abstract void Break();
|
||||
public int RegisterMark(string name)
|
||||
@ -149,8 +151,11 @@ namespace DCFApixels.DragonECS
|
||||
int id;
|
||||
if (!_nameIdTable.TryGetValue(name, out id))
|
||||
{
|
||||
id = _idDispenser.UseFree();
|
||||
_nameIdTable.Add(name, id);
|
||||
lock (_lock)
|
||||
{
|
||||
id = _idDispenser.UseFree();
|
||||
_nameIdTable.TryAdd(name, id);
|
||||
}
|
||||
}
|
||||
OnNewProfilerMark(id, name);
|
||||
return id;
|
||||
@ -158,7 +163,8 @@ namespace DCFApixels.DragonECS
|
||||
public void DeleteMark(string name)
|
||||
{
|
||||
int id = _nameIdTable[name];
|
||||
_nameIdTable.Remove(name);
|
||||
//TODO кажется этот TryRemove не подходит
|
||||
_nameIdTable.TryRemove(name, out id);
|
||||
_idDispenser.Release(id);
|
||||
OnDelProfilerMark(id);
|
||||
}
|
||||
|
@ -45,17 +45,22 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
private InitFlag _initFlags = InitFlag.None;
|
||||
|
||||
private static object _lock = new object();
|
||||
|
||||
//private EcsMemberType _memberType;
|
||||
|
||||
#region Constructors
|
||||
public static TypeMeta Get(Type type)
|
||||
{
|
||||
if (_metaCache.TryGetValue(type, out TypeMeta result) == false)
|
||||
lock (_lock)
|
||||
{
|
||||
result = new TypeMeta(type);
|
||||
_metaCache.Add(type, result);
|
||||
if (_metaCache.TryGetValue(type, out TypeMeta result) == false)
|
||||
{
|
||||
result = new TypeMeta(type);
|
||||
_metaCache.Add(type, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private TypeMeta(Type type)
|
||||
{
|
||||
|
@ -134,7 +134,7 @@ namespace DCFApixels.DragonECS
|
||||
public EcsWorld(EcsWorldConfig config, short worldID = -1) : this(config == null ? ConfigContainer.Empty : new ConfigContainer().Set(config), worldID) { }
|
||||
public EcsWorld(IConfigContainer configs = null, short worldID = -1)
|
||||
{
|
||||
lock (_lock)
|
||||
lock (_worldLock)
|
||||
{
|
||||
if (configs == null) { configs = ConfigContainer.Empty; }
|
||||
bool nullWorld = this is NullWorld;
|
||||
@ -180,7 +180,7 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
public void Destroy()
|
||||
{
|
||||
lock (_lock)
|
||||
lock (_worldLock)
|
||||
{
|
||||
if (_isDestroyed)
|
||||
{
|
||||
@ -707,7 +707,8 @@ namespace DCFApixels.DragonECS
|
||||
#endregion
|
||||
|
||||
#region Debug Components
|
||||
private static int[] _componentIDsBuffer = new int[64];
|
||||
[ThreadStatic]
|
||||
private static int[] _componentIDsBuffer;
|
||||
public ReadOnlySpan<int> GetComponentTypeIDsFor(int entityID)
|
||||
{
|
||||
int count = GetComponentTypeIDsFor(entityID, ref _componentIDsBuffer);
|
||||
@ -733,6 +734,10 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
private int GetComponentTypeIDsFor(int entityID, ref int[] componentIDs)
|
||||
{
|
||||
if (componentIDs == null)
|
||||
{
|
||||
componentIDs = new int[64];
|
||||
}
|
||||
int count = 0;
|
||||
var itemsCount = GetComponentsCount(entityID);
|
||||
if (itemsCount <= 0) { return count; }
|
||||
|
@ -3,6 +3,7 @@ using DCFApixels.DragonECS.PoolsCore;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
@ -149,80 +150,83 @@ namespace DCFApixels.DragonECS
|
||||
#region CreatePool
|
||||
private TPool CreatePool<TPool>() where TPool : IEcsPoolImplementation, new()
|
||||
{
|
||||
int poolTypeCode = EcsTypeCode.Get<TPool>();
|
||||
if (_poolTypeCode_2_CmpTypeIDs.Contains(poolTypeCode))
|
||||
lock (_worldLock)
|
||||
{
|
||||
Throw.World_PoolAlreadyCreated();
|
||||
}
|
||||
TPool newPool = new TPool();
|
||||
int poolTypeCode = EcsTypeCode.Get<TPool>();
|
||||
if (_poolTypeCode_2_CmpTypeIDs.Contains(poolTypeCode))
|
||||
{
|
||||
Throw.World_PoolAlreadyCreated();
|
||||
}
|
||||
TPool newPool = new TPool();
|
||||
|
||||
Type componentType = newPool.ComponentType;
|
||||
Type componentType = newPool.ComponentType;
|
||||
#if DEBUG //проверка соответсвия типов
|
||||
#pragma warning disable IL2090 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The generic parameter of the source method or type does not have matching annotations.
|
||||
if (componentType != typeof(TPool).GetInterfaces()
|
||||
.First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>))
|
||||
.GetGenericArguments()[0])
|
||||
{
|
||||
Throw.Exception("A custom pool must implement the interface IEcsPoolImplementation<T> where T is the type that stores the pool.");
|
||||
}
|
||||
if (componentType != typeof(TPool).GetInterfaces()
|
||||
.First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>))
|
||||
.GetGenericArguments()[0])
|
||||
{
|
||||
Throw.Exception("A custom pool must implement the interface IEcsPoolImplementation<T> where T is the type that stores the pool.");
|
||||
}
|
||||
#pragma warning restore IL2090 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The generic parameter of the source method or type does not have matching annotations.
|
||||
#endif
|
||||
int componentTypeCode = EcsTypeCode.Get(componentType);
|
||||
int componentTypeCode = EcsTypeCode.Get(componentType);
|
||||
|
||||
if (_cmpTypeCode_2_CmpTypeIDs.TryGetValue(componentTypeCode, out int componentTypeID))
|
||||
{
|
||||
_poolTypeCode_2_CmpTypeIDs[poolTypeCode] = componentTypeID;
|
||||
}
|
||||
else
|
||||
{
|
||||
componentTypeID = _poolsCount++;
|
||||
_poolTypeCode_2_CmpTypeIDs[poolTypeCode] = componentTypeID;
|
||||
_cmpTypeCode_2_CmpTypeIDs[componentTypeCode] = componentTypeID;
|
||||
}
|
||||
|
||||
if (_poolsCount >= _pools.Length)
|
||||
{
|
||||
int oldCapacity = _pools.Length;
|
||||
Array.Resize(ref _pools, _pools.Length << 1);
|
||||
Array.Resize(ref _poolSlots, _pools.Length);
|
||||
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
|
||||
|
||||
int newEntityComponentMaskLength = CalcEntityComponentMaskLength(); //_pools.Length / COMPONENT_MASK_CHUNK_SIZE + 1;
|
||||
int dif = newEntityComponentMaskLength - _entityComponentMaskLength;
|
||||
if (dif > 0)
|
||||
if (_cmpTypeCode_2_CmpTypeIDs.TryGetValue(componentTypeCode, out int componentTypeID))
|
||||
{
|
||||
int[] newEntityComponentMasks = new int[_entitiesCapacity * newEntityComponentMaskLength];
|
||||
int indxMax = _entityComponentMaskLength * _entitiesCapacity;
|
||||
int indx = 0;
|
||||
int newIndx = 0;
|
||||
int nextIndx = _entityComponentMaskLength;
|
||||
while (indx < indxMax)
|
||||
{
|
||||
while (indx < nextIndx)
|
||||
{
|
||||
newEntityComponentMasks[newIndx] = _entityComponentMasks[indx];
|
||||
indx++;
|
||||
newIndx++;
|
||||
}
|
||||
newIndx += dif;
|
||||
nextIndx += _entityComponentMaskLength;
|
||||
}
|
||||
SetEntityComponentMaskLength(newEntityComponentMaskLength);
|
||||
_entityComponentMasks = newEntityComponentMasks;
|
||||
_poolTypeCode_2_CmpTypeIDs[poolTypeCode] = componentTypeID;
|
||||
}
|
||||
else
|
||||
{
|
||||
componentTypeID = _poolsCount++;
|
||||
_poolTypeCode_2_CmpTypeIDs[poolTypeCode] = componentTypeID;
|
||||
_cmpTypeCode_2_CmpTypeIDs[componentTypeCode] = componentTypeID;
|
||||
}
|
||||
|
||||
if (_poolsCount >= _pools.Length)
|
||||
{
|
||||
int oldCapacity = _pools.Length;
|
||||
Array.Resize(ref _pools, _pools.Length << 1);
|
||||
Array.Resize(ref _poolSlots, _pools.Length);
|
||||
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
|
||||
|
||||
int newEntityComponentMaskLength = CalcEntityComponentMaskLength(); //_pools.Length / COMPONENT_MASK_CHUNK_SIZE + 1;
|
||||
int dif = newEntityComponentMaskLength - _entityComponentMaskLength;
|
||||
if (dif > 0)
|
||||
{
|
||||
int[] newEntityComponentMasks = new int[_entitiesCapacity * newEntityComponentMaskLength];
|
||||
int indxMax = _entityComponentMaskLength * _entitiesCapacity;
|
||||
int indx = 0;
|
||||
int newIndx = 0;
|
||||
int nextIndx = _entityComponentMaskLength;
|
||||
while (indx < indxMax)
|
||||
{
|
||||
while (indx < nextIndx)
|
||||
{
|
||||
newEntityComponentMasks[newIndx] = _entityComponentMasks[indx];
|
||||
indx++;
|
||||
newIndx++;
|
||||
}
|
||||
newIndx += dif;
|
||||
nextIndx += _entityComponentMaskLength;
|
||||
}
|
||||
SetEntityComponentMaskLength(newEntityComponentMaskLength);
|
||||
_entityComponentMasks = newEntityComponentMasks;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var oldPool = _pools[componentTypeID];
|
||||
|
||||
if (oldPool != _nullPool)
|
||||
{
|
||||
Throw.UndefinedException();
|
||||
}
|
||||
|
||||
_pools[componentTypeID] = newPool;
|
||||
newPool.OnInit(this, _poolsMediator, componentTypeID);
|
||||
return newPool;
|
||||
}
|
||||
|
||||
var oldPool = _pools[componentTypeID];
|
||||
|
||||
if (oldPool != _nullPool)
|
||||
{
|
||||
Throw.UndefinedException();
|
||||
}
|
||||
|
||||
_pools[componentTypeID] = newPool;
|
||||
newPool.OnInit(this, _poolsMediator, componentTypeID);
|
||||
return newPool;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
@ -31,7 +32,7 @@ namespace DCFApixels.DragonECS
|
||||
private static List<DataReleaser> _dataReleaseres = new List<DataReleaser>();
|
||||
//public static int Copacity => Worlds.Length;
|
||||
|
||||
private static readonly object _lock = new object();
|
||||
private static readonly object _worldLock = new object();
|
||||
|
||||
static EcsWorld()
|
||||
{
|
||||
@ -39,7 +40,7 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
private static void ReleaseData(int worldID)
|
||||
{// ts
|
||||
lock (_lock)
|
||||
lock (_worldLock)
|
||||
{
|
||||
for (int i = 0, iMax = _dataReleaseres.Count; i < iMax; i++)
|
||||
{
|
||||
@ -78,17 +79,15 @@ namespace DCFApixels.DragonECS
|
||||
private static short _recycledItemsCount;
|
||||
private static IEcsWorldComponent<T> _interface = EcsWorldComponentHandler<T>.instance;
|
||||
|
||||
private static readonly object _lock = new object();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ref T Get(int itemIndex)
|
||||
public static ref T GetItem(int itemIndex)
|
||||
{// ts
|
||||
return ref _items[itemIndex];
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ref T GetForWorld(int worldID)
|
||||
{// зависит от GetItemIndex
|
||||
return ref Get(GetItemIndex(worldID));
|
||||
return ref GetItem(GetItemIndex(worldID));
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ref T GetForWorldUnchecked(int worldID)
|
||||
@ -102,7 +101,7 @@ namespace DCFApixels.DragonECS
|
||||
{// ts
|
||||
if (_mapping.Length < _worlds.Length)
|
||||
{
|
||||
lock (_lock)
|
||||
lock (_worldLock)
|
||||
{
|
||||
if (_mapping.Length < _worlds.Length)
|
||||
{
|
||||
@ -114,7 +113,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
if (itemIndex == 0)
|
||||
{
|
||||
lock (_lock)
|
||||
lock (_worldLock)
|
||||
{
|
||||
itemIndex = _mapping[worldID];
|
||||
if (itemIndex <= 0)
|
||||
@ -134,6 +133,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
Array.Resize(ref _items, _items.Length << 1);
|
||||
}
|
||||
|
||||
_interface.Init(ref _items[itemIndex], _worlds[worldID]);
|
||||
_dataReleaseres.Add(new Releaser());
|
||||
}
|
||||
@ -143,7 +143,7 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
private static void Release(int worldID)
|
||||
{// ts
|
||||
lock (_lock)
|
||||
lock (_worldLock)
|
||||
{
|
||||
if (_mapping.Length < _worlds.Length)
|
||||
{
|
||||
|
@ -16,6 +16,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
{
|
||||
private static readonly Dictionary<Type, int> _codes = new Dictionary<Type, int>();
|
||||
private static int _increment = 1;
|
||||
private static object _lock = new object();
|
||||
public static int Count
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -23,12 +24,15 @@ namespace DCFApixels.DragonECS.Internal
|
||||
}
|
||||
public static int Get(Type type)
|
||||
{
|
||||
if (!_codes.TryGetValue(type, out int code))
|
||||
lock (_lock)
|
||||
{
|
||||
code = _increment++;
|
||||
_codes.Add(type, code);
|
||||
if (!_codes.TryGetValue(type, out int code))
|
||||
{
|
||||
code = _increment++;
|
||||
_codes.Add(type, code);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Get<T>() { return EcsTypeCodeCache<T>.code; }
|
||||
|
Loading…
Reference in New Issue
Block a user