refactor(state): 将状态机实现为完全异步操作并改进线程安全机制

- 添加 SemaphoreSlim 锁确保状态转换的线程安全性
- 将所有同步方法重构为异步方法并移除旧的同步实现
- 使用异步锁替代传统的 lock 机制提升并发性能
- 优化状态历史记录的处理时机和逻辑
- 移除过时的同步状态转换内部方法
- 统一异常处理和资源释放机制
This commit is contained in:
GeWuYou 2026-02-15 22:36:50 +08:00 committed by gewuyou
parent e24aacc4bc
commit 6c53626df8
2 changed files with 83 additions and 136 deletions

View File

@ -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>
@ -62,11 +53,13 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
/// </summary> /// </summary>
/// <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
{
await _transitionLock.WaitAsync();
try
{ {
var stateToUnregister = PrepareUnregister<T>(out var isCurrentState); var stateToUnregister = PrepareUnregister<T>(out var isCurrentState);
if (stateToUnregister == null) return this; if (stateToUnregister == null) return this;
// 如果是当前状态,执行异步退出
if (isCurrentState) if (isCurrentState)
{ {
await ExecuteExitAsync(Current!, null); await ExecuteExitAsync(Current!, null);
@ -76,6 +69,12 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
CompleteUnregister(stateToUnregister); CompleteUnregister(stateToUnregister);
return this; return this;
} }
finally
{
_transitionLock.Release();
}
}
/// <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>
@ -96,6 +92,9 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
/// <typeparam name="T">目标状态类型</typeparam> /// <typeparam name="T">目标状态类型</typeparam>
/// <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
{
await _transitionLock.WaitAsync();
try
{ {
if (!States.TryGetValue(typeof(T), out var target)) if (!States.TryGetValue(typeof(T), out var target))
return false; return false;
@ -104,6 +103,12 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
return await CanTransitionToAsync(Current, target); return await CanTransitionToAsync(Current, target);
} }
finally
{
_transitionLock.Release();
}
}
/// <summary> /// <summary>
/// 切换到指定类型的状态 /// 切换到指定类型的状态
@ -113,21 +118,9 @@ 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>
/// 异步切换到指定类型的状态 /// 异步切换到指定类型的状态
@ -136,6 +129,9 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
/// <returns>如果成功切换则返回true否则返回false</returns> /// <returns>如果成功切换则返回true否则返回false</returns>
/// <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
{
await _transitionLock.WaitAsync();
try
{ {
IState target; IState target;
IState? currentSnapshot; IState? currentSnapshot;
@ -145,10 +141,9 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
if (!States.TryGetValue(typeof(T), out target!)) if (!States.TryGetValue(typeof(T), out target!))
throw new InvalidOperationException($"State {typeof(T).Name} not registered."); throw new InvalidOperationException($"State {typeof(T).Name} not registered.");
currentSnapshot = Current; // 在锁内获取当前状态的快照 currentSnapshot = Current;
} }
// 验证转换(在锁外执行异步操作)
if (currentSnapshot != null) if (currentSnapshot != null)
{ {
var canTransition = await CanTransitionToAsync(currentSnapshot, target); var canTransition = await CanTransitionToAsync(currentSnapshot, target);
@ -162,6 +157,11 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
await ChangeInternalAsync(target); await ChangeInternalAsync(target);
return true; 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>
@ -234,6 +230,9 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
/// </summary> /// </summary>
/// <returns>如果成功回退则返回true否则返回false</returns> /// <returns>如果成功回退则返回true否则返回false</returns>
public async Task<bool> GoBackAsync() public async Task<bool> GoBackAsync()
{
await _transitionLock.WaitAsync();
try
{ {
var previousState = FindValidPreviousState(); var previousState = FindValidPreviousState();
if (previousState == null) return false; if (previousState == null) return false;
@ -241,6 +240,11 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
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);
} }

View File

@ -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>
/// 异步内部状态切换方法,重写基类方法以添加状态变更事件通知功能 /// 异步内部状态切换方法,重写基类方法以添加状态变更事件通知功能