Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixed several of bugs + implemented awaitable threadMgr methods #483

Merged
merged 7 commits into from
Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ private MethodInfo GetMethodInfo(Type type, string funcName)

void OnEnable()
{
if (!awaked && !isAwaking)
{
Awake();
LifeCycleMgr.Instance.ExecuteOnceTask();
}
LifeCycleMgr.Instance.AddTask(() =>
{
if (instance != null)
Expand Down
172 changes: 145 additions & 27 deletions UnityProject/Assets/Dependencies/JEngine/Core/Manager/ThreadMgr.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,116 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;

namespace JEngine.Core
{
public static class ThreadMgr
public static unsafe class ThreadMgr
{
public struct ThreadTaskAwaiter : INotifyCompletion
{
public int Index;

public void GetResult()
{
}

public bool IsCompleted
=> false;

public void OnCompleted(Action continuation)
{
Actions[Index] = continuation;
}

public ThreadTaskAwaiter GetAwaiter()
{
return this;
}
}

private static int GetIndex()
{
bool gotLock = false;
try
{
_createLock.Enter(ref gotLock);
byte* ptr = UsageList;
byte* max = ptr + MaxSize;
while (ptr < max)
{
if (*ptr == 0)
{
*ptr = 1;
break;
}

ptr++;
}

if (ptr == max)
throw new Exception("ThreadMgr: ThreadTaskAwaiter is full!");

return (int)(ptr - UsageList);
}
finally
{
if (gotLock) _createLock.Exit();
}
}

private static void SetCompleted(int index)
{
if (UsageList[index] == 0 || index < 0 || index >= MaxSize)
return;
Action act = Actions[index];
try
{
UsageList[index] = 0;
act?.Invoke();
}
catch (Exception e)
{
Debug.LogException(e);
}
}

/// <summary>
/// Init loom
/// 待执行任务
/// </summary>
private static readonly Action[] Actions = new Action[MaxSize];

/// <summary>
/// 使用列表
/// </summary>
private static readonly byte* UsageList = (byte*)UnsafeUtility.Malloc(MaxSize, 4, Allocator.Persistent);

/// <summary>
/// 最大数量
/// </summary>
private const int MaxSize = 10000;

/// <summary>
/// 锁
/// </summary>
private static SpinLock _createLock;


/// <summary>
/// Init ThreadMgr
/// </summary>
public static void Initialize()
{
//注册Update到LifeCycleMgr
_updateTaskId = LifeCycleMgr.Instance.AddUpdateTask(Update, () => _active);
//默认运行
Activate();
GC.AddMemoryPressure(MaxSize);
}

/// <summary>
Expand All @@ -29,23 +124,23 @@ public static void Initialize()
private static bool _active;

/// <summary>
/// Activate loom to execute loop
/// Activate threadMgr to execute loop
/// </summary>
public static void Activate()
{
_active = true;
}

/// <summary>
/// Deactivate loom to stop loop
/// Deactivate threadMgr to stop loop
/// </summary>
public static void Deactivate()
{
_active = false;
}

/// <summary>
/// Stop the current loom, requires re-initialize to rerun
/// Stop the current threadMgr, requires re-initialize to rerun
/// </summary>
public static void Stop()
{
Expand Down Expand Up @@ -73,59 +168,82 @@ private struct DelayedQueueItem
/// <param name="action"></param>
/// <param name="p"></param>
[Obsolete("Use QueueOnMainThread<T> instead")]
public static void QueueOnMainThread(Action<object> action, object p)
{
QueueOnMainThread(action, p, 0f);
}
public static ThreadTaskAwaiter QueueOnMainThread(Action<object> action, object p)
=> QueueOnMainThread(action, p, 0f);

/// <summary>
/// Queue an action with param on main thread to run after specific seconds
/// </summary>
/// <param name="action"></param>
/// <param name="p"></param>
/// <param name="time"></param>
public static void QueueOnMainThread<T>(Action<T> action, T p, float time = 0)
public static ThreadTaskAwaiter QueueOnMainThread<T>(Action<T> action, T p, float time = 0)
{
QueueOnMainThread(() => action(p), time);
var ret = new ThreadTaskAwaiter();
ret.Index = GetIndex();
int index = ret.Index;
var act = new Action(() =>
{
action(p);
SetCompleted(index);
});
Delayed.Enqueue(new DelayedQueueItem { Time = _curTime + time, Action = act, MainThread = true });
return ret;
}

/// <summary>
/// Queue an action on main thread to run after specific seconds
/// </summary>
/// <param name="action"></param>
/// <param name="time"></param>
public static void QueueOnMainThread(Action action, float time = 0f)
public static ThreadTaskAwaiter QueueOnMainThread(Action action, float time = 0f)
{
Delayed.Enqueue(new DelayedQueueItem { Time = _curTime + time, Action = action, MainThread = true});
var ret = new ThreadTaskAwaiter();
int index = GetIndex();
ret.Index = index;
var act = new Action(() =>
{
action();
SetCompleted(index);
});
Delayed.Enqueue(new DelayedQueueItem { Time = _curTime + time, Action = act, MainThread = true });
return ret;
}

/// <summary>
/// Queue an action on other thread to run after specific seconds
/// </summary>
/// <param name="action"></param>
/// <param name="p"></param>
/// <param name="time"></param>
/// <typeparam name="T"></typeparam>
public static void QueueOnOtherThread<T>(Action<T> action, T p, float time = 0f)
{
QueueOnOtherThread(() => action(p), time);
}
public static ThreadTaskAwaiter QueueOnOtherThread<T>(Action<T> action, T p, float time = 0f)
=> QueueOnMainThread(action, p, time);

/// <summary>
/// Queue an action on other thread to run after specific seconds
/// </summary>
/// <param name="action"></param>
/// <param name="time"></param>
public static void QueueOnOtherThread(Action action, float time = 0f)
public static ThreadTaskAwaiter QueueOnOtherThread(Action action, float time = 0f)
{
Delayed.Enqueue(new DelayedQueueItem { Time = _curTime + time, Action = action , MainThread = false});
var ret = new ThreadTaskAwaiter();
int index = GetIndex();
ret.Index = index;
var act = new Action(() =>
{
action();
SetCompleted(index);
});
Delayed.Enqueue(new DelayedQueueItem { Time = _curTime + time, Action = act, MainThread = false });
return ret;
}

/// <summary>
/// Current actions to process
/// </summary>
private static readonly List<(bool main, Action action)> CurActions = new List<(bool, Action)>(100);

/// <summary>
/// Current time
/// </summary>
Expand All @@ -136,7 +254,7 @@ public static void QueueOnOtherThread(Action action, float time = 0f)
/// </summary>
static void Update()
{
_curTime = UnityEngine.Time.time;
_curTime = Time.time;
var i = Delayed.Count;
while (i-- > 0)
{
Expand All @@ -147,11 +265,11 @@ static void Update()
}
else
{
Delayed.Enqueue(item);
Delayed.Enqueue(item);
}
}

foreach (var (main,act) in CurActions)
foreach (var (main, act) in CurActions)
{
if (!main)
{
Expand All @@ -163,7 +281,7 @@ static void Update()
}
catch (Exception e)
{
UnityEngine.Debug.LogException(e);
Debug.LogException(e);
}
});
}
Expand All @@ -175,7 +293,7 @@ static void Update()
}
catch (Exception e)
{
UnityEngine.Debug.LogException(e);
Debug.LogException(e);
}
}
}
Expand Down
28 changes: 20 additions & 8 deletions UnityProject/Assets/Dependencies/JEngine/Core/Util/ClassBind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public void BindSelf()
private static readonly Type MonoAdapterType = typeof(MonoBehaviourAdapter.Adaptor);
private static readonly Type ILTypeInstanceType = typeof(ILTypeInstance);
private static readonly Type AppdomainType = typeof(AppDomain);

private const BindingFlags AllBindingFlags = BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.Static |
BindingFlags.FlattenHierarchy | BindingFlags.Default;
Expand Down Expand Up @@ -175,18 +176,29 @@ void BindVal(ClassField field, object obj)
try
{
var fi = t.GetField(field.fieldName, AllBindingFlags);
if (fi == null) fi = t.BaseType?.GetField(field.fieldName, AllBindingFlags);
var type = t;
while (fi == null && type.BaseType != null)
{
fi = type.BaseType.GetField(field.fieldName, AllBindingFlags);
type = type.BaseType;
}

if (fi != null)
{
fi.SetValue(clrInstance.ILInstance, obj);
}
else
{
var pi = t.GetProperty(field.fieldName, AllBindingFlags);
if (pi == null) pi = t.BaseType?.GetProperty(field.fieldName, AllBindingFlags);
if (pi == null)
throw new NullReferenceException();
pi.SetValue(clrInstance.ILInstance, obj);
type = t;
while (pi == null && type.BaseType != null)
{
pi = type.BaseType.GetProperty(field.fieldName, AllBindingFlags);
type = type.BaseType;
}

if (pi != null)
pi.SetValue(clrInstance.ILInstance, obj);
}
}
catch (Exception e)
Expand Down Expand Up @@ -418,7 +430,7 @@ void SetField(Type fieldType)
}

obj = o;
BindVal(field,obj);
BindVal(field, obj);
});
classData.BoundData = true;
continue;
Expand Down Expand Up @@ -457,7 +469,7 @@ public void Active(ClassData classData)
Log.PrintError($"自动绑定{name}出错:{classType}没有成功绑定数据,自动激活成功,但可能会抛出空异常!");
}

if (classData.ClrInstance is MonoBehaviourAdapter.Adaptor mb)
if (classData.ClrInstance is MonoBehaviourAdapter.Adaptor mb)
{
mb.Awake();
}
Expand All @@ -471,7 +483,7 @@ public void Active(ClassData classData)
var flags = BindingFlags.Default | BindingFlags.Public
| BindingFlags.Instance | BindingFlags.FlattenHierarchy |
BindingFlags.NonPublic | BindingFlags.Static;
var awakeMethod = clrInstance.GetType().GetMethod("Awake",flags);
var awakeMethod = clrInstance.GetType().GetMethod("Awake", flags);
if (awakeMethod == null)
{
awakeMethod = t.GetMethod("Awake", flags);
Expand Down
Loading