mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-25 21:34:28 +08:00
refactor(state): 将状态机实现为完全异步操作并改进线程安全机制
- 添加 SemaphoreSlim 锁确保状态转换的线程安全性 - 将所有同步方法重构为异步方法并移除旧的同步实现 - 使用异步锁替代传统的 lock 机制提升并发性能 - 优化状态历史记录的处理时机和逻辑 - 移除过时的同步状态转换内部方法 - 统一异常处理和资源释放机制
This commit is contained in:
parent
e24aacc4bc
commit
6c53626df8
@ -9,8 +9,10 @@ namespace GFramework.Core.state;
|
|||||||
public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||||
{
|
{
|
||||||
private readonly object _lock = new();
|
private readonly object _lock = new();
|
||||||
private readonly HashSet<IState> _registeredStates = new(); // 优化:用于快速检查状态是否注册
|
|
||||||
|
private readonly HashSet<IState> _registeredStates = [];
|
||||||
private readonly Stack<IState> _stateHistory = new();
|
private readonly Stack<IState> _stateHistory = new();
|
||||||
|
private readonly SemaphoreSlim _transitionLock = new(1, 1);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 存储所有已注册状态的字典,键为状态类型,值为状态实例
|
/// 存储所有已注册状态的字典,键为状态类型,值为状态实例
|
||||||
@ -43,18 +45,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <typeparam name="T">要注销的状态类型</typeparam>
|
/// <typeparam name="T">要注销的状态类型</typeparam>
|
||||||
public IStateMachine Unregister<T>() where T : IState
|
public IStateMachine Unregister<T>() where T : IState
|
||||||
{
|
{
|
||||||
var stateToUnregister = PrepareUnregister<T>(out var isCurrentState);
|
return UnregisterAsync<T>().GetAwaiter().GetResult();
|
||||||
if (stateToUnregister == null) return this;
|
|
||||||
|
|
||||||
// 如果是当前状态,执行同步退出
|
|
||||||
if (isCurrentState)
|
|
||||||
{
|
|
||||||
Current!.OnExit(null);
|
|
||||||
Current = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
CompleteUnregister(stateToUnregister);
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -63,20 +54,28 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <typeparam name="T">要注销的状态类型</typeparam>
|
/// <typeparam name="T">要注销的状态类型</typeparam>
|
||||||
public async Task<IStateMachine> UnregisterAsync<T>() where T : IState
|
public async Task<IStateMachine> UnregisterAsync<T>() where T : IState
|
||||||
{
|
{
|
||||||
var stateToUnregister = PrepareUnregister<T>(out var isCurrentState);
|
await _transitionLock.WaitAsync();
|
||||||
if (stateToUnregister == null) return this;
|
try
|
||||||
|
|
||||||
// 如果是当前状态,执行异步退出
|
|
||||||
if (isCurrentState)
|
|
||||||
{
|
{
|
||||||
await ExecuteExitAsync(Current!, null);
|
var stateToUnregister = PrepareUnregister<T>(out var isCurrentState);
|
||||||
Current = null;
|
if (stateToUnregister == null) return this;
|
||||||
}
|
|
||||||
|
|
||||||
CompleteUnregister(stateToUnregister);
|
if (isCurrentState)
|
||||||
return this;
|
{
|
||||||
|
await ExecuteExitAsync(Current!, null);
|
||||||
|
Current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompleteUnregister(stateToUnregister);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_transitionLock.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查是否可以切换到指定类型的状态
|
/// 检查是否可以切换到指定类型的状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -84,10 +83,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <returns>如果可以切换则返回true,否则返回false</returns>
|
/// <returns>如果可以切换则返回true,否则返回false</returns>
|
||||||
public bool CanChangeTo<T>() where T : IState
|
public bool CanChangeTo<T>() where T : IState
|
||||||
{
|
{
|
||||||
if (!States.TryGetValue(typeof(T), out var target))
|
return CanChangeToAsync<T>().GetAwaiter().GetResult();
|
||||||
return false;
|
|
||||||
|
|
||||||
return Current?.CanTransitionTo(target) ?? true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -97,14 +93,23 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <returns>如果可以切换则返回true,否则返回false</returns>
|
/// <returns>如果可以切换则返回true,否则返回false</returns>
|
||||||
public async Task<bool> CanChangeToAsync<T>() where T : IState
|
public async Task<bool> CanChangeToAsync<T>() where T : IState
|
||||||
{
|
{
|
||||||
if (!States.TryGetValue(typeof(T), out var target))
|
await _transitionLock.WaitAsync();
|
||||||
return false;
|
try
|
||||||
|
{
|
||||||
|
if (!States.TryGetValue(typeof(T), out var target))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (Current == null) return true;
|
if (Current == null) return true;
|
||||||
|
|
||||||
return await CanTransitionToAsync(Current, target);
|
return await CanTransitionToAsync(Current, target);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_transitionLock.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 切换到指定类型的状态
|
/// 切换到指定类型的状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -113,22 +118,10 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <exception cref="InvalidOperationException">当目标状态未注册时抛出</exception>
|
/// <exception cref="InvalidOperationException">当目标状态未注册时抛出</exception>
|
||||||
public bool ChangeTo<T>() where T : IState
|
public bool ChangeTo<T>() where T : IState
|
||||||
{
|
{
|
||||||
lock (_lock)
|
return ChangeToAsync<T>().GetAwaiter().GetResult();
|
||||||
{
|
|
||||||
if (!States.TryGetValue(typeof(T), out var target))
|
|
||||||
throw new InvalidOperationException($"State {typeof(T).Name} not registered.");
|
|
||||||
|
|
||||||
if (Current != null && !Current.CanTransitionTo(target))
|
|
||||||
{
|
|
||||||
OnTransitionRejected(Current, target);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChangeInternal(target);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步切换到指定类型的状态
|
/// 异步切换到指定类型的状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -137,30 +130,37 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <exception cref="InvalidOperationException">当目标状态未注册时抛出</exception>
|
/// <exception cref="InvalidOperationException">当目标状态未注册时抛出</exception>
|
||||||
public async Task<bool> ChangeToAsync<T>() where T : IState
|
public async Task<bool> ChangeToAsync<T>() where T : IState
|
||||||
{
|
{
|
||||||
IState target;
|
await _transitionLock.WaitAsync();
|
||||||
IState? currentSnapshot;
|
try
|
||||||
|
|
||||||
lock (_lock)
|
|
||||||
{
|
{
|
||||||
if (!States.TryGetValue(typeof(T), out target!))
|
IState target;
|
||||||
throw new InvalidOperationException($"State {typeof(T).Name} not registered.");
|
IState? currentSnapshot;
|
||||||
|
|
||||||
currentSnapshot = Current; // 在锁内获取当前状态的快照
|
lock (_lock)
|
||||||
}
|
|
||||||
|
|
||||||
// 验证转换(在锁外执行异步操作)
|
|
||||||
if (currentSnapshot != null)
|
|
||||||
{
|
|
||||||
var canTransition = await CanTransitionToAsync(currentSnapshot, target);
|
|
||||||
if (!canTransition)
|
|
||||||
{
|
{
|
||||||
await OnTransitionRejectedAsync(currentSnapshot, target);
|
if (!States.TryGetValue(typeof(T), out target!))
|
||||||
return false;
|
throw new InvalidOperationException($"State {typeof(T).Name} not registered.");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await ChangeInternalAsync(target);
|
currentSnapshot = Current;
|
||||||
return true;
|
}
|
||||||
|
|
||||||
|
if (currentSnapshot != null)
|
||||||
|
{
|
||||||
|
var canTransition = await CanTransitionToAsync(currentSnapshot, target);
|
||||||
|
if (!canTransition)
|
||||||
|
{
|
||||||
|
await OnTransitionRejectedAsync(currentSnapshot, target);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await ChangeInternalAsync(target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_transitionLock.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -222,11 +222,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
||||||
public bool GoBack()
|
public bool GoBack()
|
||||||
{
|
{
|
||||||
var previousState = FindValidPreviousState();
|
return GoBackAsync().GetAwaiter().GetResult();
|
||||||
if (previousState == null) return false;
|
|
||||||
|
|
||||||
ChangeInternalWithoutHistory(previousState);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -235,11 +231,19 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
||||||
public async Task<bool> GoBackAsync()
|
public async Task<bool> GoBackAsync()
|
||||||
{
|
{
|
||||||
var previousState = FindValidPreviousState();
|
await _transitionLock.WaitAsync();
|
||||||
if (previousState == null) return false;
|
try
|
||||||
|
{
|
||||||
|
var previousState = FindValidPreviousState();
|
||||||
|
if (previousState == null) return false;
|
||||||
|
|
||||||
await ChangeInternalWithoutHistoryAsync(previousState);
|
await ChangeInternalWithoutHistoryAsync(previousState);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_transitionLock.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -310,24 +314,6 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 内部状态切换方法(不记录历史),用于回退操作
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="next">下一个状态实例</param>
|
|
||||||
protected virtual void ChangeInternalWithoutHistory(IState next)
|
|
||||||
{
|
|
||||||
if (Current == next) return;
|
|
||||||
|
|
||||||
var old = Current;
|
|
||||||
OnStateChanging(old, next);
|
|
||||||
|
|
||||||
old?.OnExit(next);
|
|
||||||
Current = next;
|
|
||||||
Current.OnEnter(old);
|
|
||||||
|
|
||||||
OnStateChanged(old, Current);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步内部状态切换方法(不记录历史),用于回退操作
|
/// 异步内部状态切换方法(不记录历史),用于回退操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -346,32 +332,6 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
await OnStateChangedAsync(old, Current);
|
await OnStateChangedAsync(old, Current);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 内部状态切换方法,处理状态切换的核心逻辑
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="next">下一个状态实例</param>
|
|
||||||
protected virtual void ChangeInternal(IState next)
|
|
||||||
{
|
|
||||||
if (Current == next) return;
|
|
||||||
|
|
||||||
if (Current != null && !Current.CanTransitionTo(next))
|
|
||||||
{
|
|
||||||
OnTransitionRejected(Current, next);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var old = Current;
|
|
||||||
OnStateChanging(old, next);
|
|
||||||
|
|
||||||
AddToHistory(Current);
|
|
||||||
|
|
||||||
old?.OnExit(next);
|
|
||||||
Current = next;
|
|
||||||
Current.OnEnter(old);
|
|
||||||
|
|
||||||
OnStateChanged(old, Current);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步内部状态切换方法,处理状态切换的核心逻辑
|
/// 异步内部状态切换方法,处理状态切换的核心逻辑
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -383,12 +343,15 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
|||||||
var old = Current;
|
var old = Current;
|
||||||
await OnStateChangingAsync(old, next);
|
await OnStateChangingAsync(old, next);
|
||||||
|
|
||||||
AddToHistory(Current);
|
|
||||||
|
|
||||||
await ExecuteExitAsync(old, next);
|
await ExecuteExitAsync(old, next);
|
||||||
|
|
||||||
|
AddToHistory(old);
|
||||||
|
|
||||||
Current = next;
|
Current = next;
|
||||||
|
|
||||||
await ExecuteEnterAsync(Current, old);
|
await ExecuteEnterAsync(Current, old);
|
||||||
|
|
||||||
|
|
||||||
await OnStateChangedAsync(old, Current);
|
await OnStateChangedAsync(old, Current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -71,22 +71,6 @@ public class StateMachineSystem : StateMachine, IStateMachineSystem
|
|||||||
States.Clear();
|
States.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 内部状态切换方法,重写基类方法以添加状态变更事件通知功能
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="next">要切换到的下一个状态</param>
|
|
||||||
protected override void ChangeInternal(IState next)
|
|
||||||
{
|
|
||||||
var old = Current;
|
|
||||||
base.ChangeInternal(next);
|
|
||||||
|
|
||||||
// 发送状态变更事件,通知监听者状态已发生改变
|
|
||||||
this.SendEvent(new StateChangedEvent
|
|
||||||
{
|
|
||||||
OldState = old,
|
|
||||||
NewState = Current
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步内部状态切换方法,重写基类方法以添加状态变更事件通知功能
|
/// 异步内部状态切换方法,重写基类方法以添加状态变更事件通知功能
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user