mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-23 19:24:29 +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
|
||||
{
|
||||
private readonly object _lock = new();
|
||||
private readonly HashSet<IState> _registeredStates = new(); // 优化:用于快速检查状态是否注册
|
||||
|
||||
private readonly HashSet<IState> _registeredStates = [];
|
||||
private readonly Stack<IState> _stateHistory = new();
|
||||
private readonly SemaphoreSlim _transitionLock = new(1, 1);
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有已注册状态的字典,键为状态类型,值为状态实例
|
||||
@ -43,18 +45,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
/// <typeparam name="T">要注销的状态类型</typeparam>
|
||||
public IStateMachine Unregister<T>() where T : IState
|
||||
{
|
||||
var stateToUnregister = PrepareUnregister<T>(out var isCurrentState);
|
||||
if (stateToUnregister == null) return this;
|
||||
|
||||
// 如果是当前状态,执行同步退出
|
||||
if (isCurrentState)
|
||||
{
|
||||
Current!.OnExit(null);
|
||||
Current = null;
|
||||
}
|
||||
|
||||
CompleteUnregister(stateToUnregister);
|
||||
return this;
|
||||
return UnregisterAsync<T>().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -63,20 +54,28 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
/// <typeparam name="T">要注销的状态类型</typeparam>
|
||||
public async Task<IStateMachine> UnregisterAsync<T>() where T : IState
|
||||
{
|
||||
var stateToUnregister = PrepareUnregister<T>(out var isCurrentState);
|
||||
if (stateToUnregister == null) return this;
|
||||
|
||||
// 如果是当前状态,执行异步退出
|
||||
if (isCurrentState)
|
||||
await _transitionLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
await ExecuteExitAsync(Current!, null);
|
||||
Current = null;
|
||||
}
|
||||
var stateToUnregister = PrepareUnregister<T>(out var isCurrentState);
|
||||
if (stateToUnregister == null) return this;
|
||||
|
||||
CompleteUnregister(stateToUnregister);
|
||||
return this;
|
||||
if (isCurrentState)
|
||||
{
|
||||
await ExecuteExitAsync(Current!, null);
|
||||
Current = null;
|
||||
}
|
||||
|
||||
CompleteUnregister(stateToUnregister);
|
||||
return this;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_transitionLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否可以切换到指定类型的状态
|
||||
/// </summary>
|
||||
@ -84,10 +83,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
/// <returns>如果可以切换则返回true,否则返回false</returns>
|
||||
public bool CanChangeTo<T>() where T : IState
|
||||
{
|
||||
if (!States.TryGetValue(typeof(T), out var target))
|
||||
return false;
|
||||
|
||||
return Current?.CanTransitionTo(target) ?? true;
|
||||
return CanChangeToAsync<T>().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -97,14 +93,23 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
/// <returns>如果可以切换则返回true,否则返回false</returns>
|
||||
public async Task<bool> CanChangeToAsync<T>() where T : IState
|
||||
{
|
||||
if (!States.TryGetValue(typeof(T), out var target))
|
||||
return false;
|
||||
await _transitionLock.WaitAsync();
|
||||
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>
|
||||
@ -113,22 +118,10 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
/// <exception cref="InvalidOperationException">当目标状态未注册时抛出</exception>
|
||||
public bool ChangeTo<T>() where T : IState
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
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;
|
||||
}
|
||||
return ChangeToAsync<T>().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步切换到指定类型的状态
|
||||
/// </summary>
|
||||
@ -137,30 +130,37 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
/// <exception cref="InvalidOperationException">当目标状态未注册时抛出</exception>
|
||||
public async Task<bool> ChangeToAsync<T>() where T : IState
|
||||
{
|
||||
IState target;
|
||||
IState? currentSnapshot;
|
||||
|
||||
lock (_lock)
|
||||
await _transitionLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
if (!States.TryGetValue(typeof(T), out target!))
|
||||
throw new InvalidOperationException($"State {typeof(T).Name} not registered.");
|
||||
IState target;
|
||||
IState? currentSnapshot;
|
||||
|
||||
currentSnapshot = Current; // 在锁内获取当前状态的快照
|
||||
}
|
||||
|
||||
// 验证转换(在锁外执行异步操作)
|
||||
if (currentSnapshot != null)
|
||||
{
|
||||
var canTransition = await CanTransitionToAsync(currentSnapshot, target);
|
||||
if (!canTransition)
|
||||
lock (_lock)
|
||||
{
|
||||
await OnTransitionRejectedAsync(currentSnapshot, target);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!States.TryGetValue(typeof(T), out target!))
|
||||
throw new InvalidOperationException($"State {typeof(T).Name} not registered.");
|
||||
|
||||
await ChangeInternalAsync(target);
|
||||
return true;
|
||||
currentSnapshot = Current;
|
||||
}
|
||||
|
||||
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>
|
||||
@ -222,11 +222,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
||||
public bool GoBack()
|
||||
{
|
||||
var previousState = FindValidPreviousState();
|
||||
if (previousState == null) return false;
|
||||
|
||||
ChangeInternalWithoutHistory(previousState);
|
||||
return true;
|
||||
return GoBackAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -235,11 +231,19 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
/// <returns>如果成功回退则返回true,否则返回false</returns>
|
||||
public async Task<bool> GoBackAsync()
|
||||
{
|
||||
var previousState = FindValidPreviousState();
|
||||
if (previousState == null) return false;
|
||||
await _transitionLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
var previousState = FindValidPreviousState();
|
||||
if (previousState == null) return false;
|
||||
|
||||
await ChangeInternalWithoutHistoryAsync(previousState);
|
||||
return true;
|
||||
await ChangeInternalWithoutHistoryAsync(previousState);
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_transitionLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
@ -346,32 +332,6 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
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>
|
||||
@ -383,12 +343,15 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
var old = Current;
|
||||
await OnStateChangingAsync(old, next);
|
||||
|
||||
AddToHistory(Current);
|
||||
|
||||
await ExecuteExitAsync(old, next);
|
||||
|
||||
AddToHistory(old);
|
||||
|
||||
Current = next;
|
||||
|
||||
await ExecuteEnterAsync(Current, old);
|
||||
|
||||
|
||||
await OnStateChangedAsync(old, Current);
|
||||
}
|
||||
|
||||
|
||||
@ -71,22 +71,6 @@ public class StateMachineSystem : StateMachine, IStateMachineSystem
|
||||
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>
|
||||
/// 异步内部状态切换方法,重写基类方法以添加状态变更事件通知功能
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user