fix thread safety

This commit is contained in:
Mikhail 2024-09-09 18:21:21 +08:00
parent effa02e660
commit b4af20d2ea
6 changed files with 112 additions and 88 deletions

View File

@ -1,6 +1,6 @@
using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.Internal;
using System; using System;
using System.Collections.Generic; using System.Collections.Concurrent;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -116,6 +116,8 @@ namespace DCFApixels.DragonECS
public abstract class DebugService public abstract class DebugService
{ {
private static DebugService _instance; private static DebugService _instance;
private static object _lock = new object();
public static DebugService Instance public static DebugService Instance
{ {
get get
@ -141,16 +143,19 @@ namespace DCFApixels.DragonECS
public static Action<DebugService> OnServiceChanged = delegate { }; public static Action<DebugService> OnServiceChanged = delegate { };
private IdDispenser _idDispenser = new IdDispenser(4, -1); 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 Print(string tag, object v);
public abstract void Break(); public abstract void Break();
public int RegisterMark(string name) public int RegisterMark(string name)
{ {
int id; int id;
if (!_nameIdTable.TryGetValue(name, out id)) if (!_nameIdTable.TryGetValue(name, out id))
{
lock (_lock)
{ {
id = _idDispenser.UseFree(); id = _idDispenser.UseFree();
_nameIdTable.Add(name, id); _nameIdTable.TryAdd(name, id);
}
} }
OnNewProfilerMark(id, name); OnNewProfilerMark(id, name);
return id; return id;
@ -158,7 +163,8 @@ namespace DCFApixels.DragonECS
public void DeleteMark(string name) public void DeleteMark(string name)
{ {
int id = _nameIdTable[name]; int id = _nameIdTable[name];
_nameIdTable.Remove(name); //TODO кажется этот TryRemove не подходит
_nameIdTable.TryRemove(name, out id);
_idDispenser.Release(id); _idDispenser.Release(id);
OnDelProfilerMark(id); OnDelProfilerMark(id);
} }

View File

@ -45,10 +45,14 @@ namespace DCFApixels.DragonECS
private InitFlag _initFlags = InitFlag.None; private InitFlag _initFlags = InitFlag.None;
private static object _lock = new object();
//private EcsMemberType _memberType; //private EcsMemberType _memberType;
#region Constructors #region Constructors
public static TypeMeta Get(Type type) public static TypeMeta Get(Type type)
{
lock (_lock)
{ {
if (_metaCache.TryGetValue(type, out TypeMeta result) == false) if (_metaCache.TryGetValue(type, out TypeMeta result) == false)
{ {
@ -57,6 +61,7 @@ namespace DCFApixels.DragonECS
} }
return result; return result;
} }
}
private TypeMeta(Type type) private TypeMeta(Type type)
{ {
_type = type; _type = type;

View File

@ -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(EcsWorldConfig config, short worldID = -1) : this(config == null ? ConfigContainer.Empty : new ConfigContainer().Set(config), worldID) { }
public EcsWorld(IConfigContainer configs = null, short worldID = -1) public EcsWorld(IConfigContainer configs = null, short worldID = -1)
{ {
lock (_lock) lock (_worldLock)
{ {
if (configs == null) { configs = ConfigContainer.Empty; } if (configs == null) { configs = ConfigContainer.Empty; }
bool nullWorld = this is NullWorld; bool nullWorld = this is NullWorld;
@ -180,7 +180,7 @@ namespace DCFApixels.DragonECS
} }
public void Destroy() public void Destroy()
{ {
lock (_lock) lock (_worldLock)
{ {
if (_isDestroyed) if (_isDestroyed)
{ {
@ -707,7 +707,8 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Debug Components #region Debug Components
private static int[] _componentIDsBuffer = new int[64]; [ThreadStatic]
private static int[] _componentIDsBuffer;
public ReadOnlySpan<int> GetComponentTypeIDsFor(int entityID) public ReadOnlySpan<int> GetComponentTypeIDsFor(int entityID)
{ {
int count = GetComponentTypeIDsFor(entityID, ref _componentIDsBuffer); int count = GetComponentTypeIDsFor(entityID, ref _componentIDsBuffer);
@ -733,6 +734,10 @@ namespace DCFApixels.DragonECS
} }
private int GetComponentTypeIDsFor(int entityID, ref int[] componentIDs) private int GetComponentTypeIDsFor(int entityID, ref int[] componentIDs)
{ {
if (componentIDs == null)
{
componentIDs = new int[64];
}
int count = 0; int count = 0;
var itemsCount = GetComponentsCount(entityID); var itemsCount = GetComponentsCount(entityID);
if (itemsCount <= 0) { return count; } if (itemsCount <= 0) { return count; }

View File

@ -3,6 +3,7 @@ using DCFApixels.DragonECS.PoolsCore;
using System; using System;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
@ -148,6 +149,8 @@ namespace DCFApixels.DragonECS
#region CreatePool #region CreatePool
private TPool CreatePool<TPool>() where TPool : IEcsPoolImplementation, new() private TPool CreatePool<TPool>() where TPool : IEcsPoolImplementation, new()
{
lock (_worldLock)
{ {
int poolTypeCode = EcsTypeCode.Get<TPool>(); int poolTypeCode = EcsTypeCode.Get<TPool>();
if (_poolTypeCode_2_CmpTypeIDs.Contains(poolTypeCode)) if (_poolTypeCode_2_CmpTypeIDs.Contains(poolTypeCode))
@ -224,6 +227,7 @@ namespace DCFApixels.DragonECS
newPool.OnInit(this, _poolsMediator, componentTypeID); newPool.OnInit(this, _poolsMediator, componentTypeID);
return newPool; return newPool;
} }
}
#endregion #endregion
#region Pools mediation #region Pools mediation

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
@ -31,7 +32,7 @@ namespace DCFApixels.DragonECS
private static List<DataReleaser> _dataReleaseres = new List<DataReleaser>(); private static List<DataReleaser> _dataReleaseres = new List<DataReleaser>();
//public static int Copacity => Worlds.Length; //public static int Copacity => Worlds.Length;
private static readonly object _lock = new object(); private static readonly object _worldLock = new object();
static EcsWorld() static EcsWorld()
{ {
@ -39,7 +40,7 @@ namespace DCFApixels.DragonECS
} }
private static void ReleaseData(int worldID) private static void ReleaseData(int worldID)
{// ts {// ts
lock (_lock) lock (_worldLock)
{ {
for (int i = 0, iMax = _dataReleaseres.Count; i < iMax; i++) for (int i = 0, iMax = _dataReleaseres.Count; i < iMax; i++)
{ {
@ -78,17 +79,15 @@ namespace DCFApixels.DragonECS
private static short _recycledItemsCount; private static short _recycledItemsCount;
private static IEcsWorldComponent<T> _interface = EcsWorldComponentHandler<T>.instance; private static IEcsWorldComponent<T> _interface = EcsWorldComponentHandler<T>.instance;
private static readonly object _lock = new object();
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T Get(int itemIndex) public static ref T GetItem(int itemIndex)
{// ts {// ts
return ref _items[itemIndex]; return ref _items[itemIndex];
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T GetForWorld(int worldID) public static ref T GetForWorld(int worldID)
{// зависит от GetItemIndex {// зависит от GetItemIndex
return ref Get(GetItemIndex(worldID)); return ref GetItem(GetItemIndex(worldID));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T GetForWorldUnchecked(int worldID) public static ref T GetForWorldUnchecked(int worldID)
@ -102,7 +101,7 @@ namespace DCFApixels.DragonECS
{// ts {// ts
if (_mapping.Length < _worlds.Length) if (_mapping.Length < _worlds.Length)
{ {
lock (_lock) lock (_worldLock)
{ {
if (_mapping.Length < _worlds.Length) if (_mapping.Length < _worlds.Length)
{ {
@ -114,7 +113,7 @@ namespace DCFApixels.DragonECS
if (itemIndex == 0) if (itemIndex == 0)
{ {
lock (_lock) lock (_worldLock)
{ {
itemIndex = _mapping[worldID]; itemIndex = _mapping[worldID];
if (itemIndex <= 0) if (itemIndex <= 0)
@ -134,6 +133,7 @@ namespace DCFApixels.DragonECS
{ {
Array.Resize(ref _items, _items.Length << 1); Array.Resize(ref _items, _items.Length << 1);
} }
_interface.Init(ref _items[itemIndex], _worlds[worldID]); _interface.Init(ref _items[itemIndex], _worlds[worldID]);
_dataReleaseres.Add(new Releaser()); _dataReleaseres.Add(new Releaser());
} }
@ -143,7 +143,7 @@ namespace DCFApixels.DragonECS
} }
private static void Release(int worldID) private static void Release(int worldID)
{// ts {// ts
lock (_lock) lock (_worldLock)
{ {
if (_mapping.Length < _worlds.Length) if (_mapping.Length < _worlds.Length)
{ {

View File

@ -16,12 +16,15 @@ namespace DCFApixels.DragonECS.Internal
{ {
private static readonly Dictionary<Type, int> _codes = new Dictionary<Type, int>(); private static readonly Dictionary<Type, int> _codes = new Dictionary<Type, int>();
private static int _increment = 1; private static int _increment = 1;
private static object _lock = new object();
public static int Count public static int Count
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _codes.Count; } get { return _codes.Count; }
} }
public static int Get(Type type) public static int Get(Type type)
{
lock (_lock)
{ {
if (!_codes.TryGetValue(type, out int code)) if (!_codes.TryGetValue(type, out int code))
{ {
@ -30,6 +33,7 @@ namespace DCFApixels.DragonECS.Internal
} }
return code; return code;
} }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Get<T>() { return EcsTypeCodeCache<T>.code; } public static int Get<T>() { return EcsTypeCodeCache<T>.code; }
public static bool Has(Type type) { return _codes.ContainsKey(type); } public static bool Has(Type type) { return _codes.ContainsKey(type); }