From 6c53626df8c65a110e7c3128174084a72995b8db Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Sun, 15 Feb 2026 22:36:50 +0800 Subject: [PATCH] =?UTF-8?q?refactor(state):=20=E5=B0=86=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E6=9C=BA=E5=AE=9E=E7=8E=B0=E4=B8=BA=E5=AE=8C=E5=85=A8=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E6=93=8D=E4=BD=9C=E5=B9=B6=E6=94=B9=E8=BF=9B=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E5=AE=89=E5=85=A8=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 SemaphoreSlim 锁确保状态转换的线程安全性 - 将所有同步方法重构为异步方法并移除旧的同步实现 - 使用异步锁替代传统的 lock 机制提升并发性能 - 优化状态历史记录的处理时机和逻辑 - 移除过时的同步状态转换内部方法 - 统一异常处理和资源释放机制 --- GFramework.Core/state/StateMachine.cs | 203 ++++++++------------ GFramework.Core/state/StateMachineSystem.cs | 16 -- 2 files changed, 83 insertions(+), 136 deletions(-) diff --git a/GFramework.Core/state/StateMachine.cs b/GFramework.Core/state/StateMachine.cs index 4ffd820..178dc94 100644 --- a/GFramework.Core/state/StateMachine.cs +++ b/GFramework.Core/state/StateMachine.cs @@ -9,8 +9,10 @@ namespace GFramework.Core.state; public class StateMachine(int maxHistorySize = 10) : IStateMachine { private readonly object _lock = new(); - private readonly HashSet _registeredStates = new(); // 优化:用于快速检查状态是否注册 + + private readonly HashSet _registeredStates = []; private readonly Stack _stateHistory = new(); + private readonly SemaphoreSlim _transitionLock = new(1, 1); /// /// 存储所有已注册状态的字典,键为状态类型,值为状态实例 @@ -43,18 +45,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine /// 要注销的状态类型 public IStateMachine Unregister() where T : IState { - var stateToUnregister = PrepareUnregister(out var isCurrentState); - if (stateToUnregister == null) return this; - - // 如果是当前状态,执行同步退出 - if (isCurrentState) - { - Current!.OnExit(null); - Current = null; - } - - CompleteUnregister(stateToUnregister); - return this; + return UnregisterAsync().GetAwaiter().GetResult(); } /// @@ -63,20 +54,28 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine /// 要注销的状态类型 public async Task UnregisterAsync() where T : IState { - var stateToUnregister = PrepareUnregister(out var isCurrentState); - if (stateToUnregister == null) return this; - - // 如果是当前状态,执行异步退出 - if (isCurrentState) + await _transitionLock.WaitAsync(); + try { - await ExecuteExitAsync(Current!, null); - Current = null; - } + var stateToUnregister = PrepareUnregister(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(); + } } + /// /// 检查是否可以切换到指定类型的状态 /// @@ -84,10 +83,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine /// 如果可以切换则返回true,否则返回false public bool CanChangeTo() where T : IState { - if (!States.TryGetValue(typeof(T), out var target)) - return false; - - return Current?.CanTransitionTo(target) ?? true; + return CanChangeToAsync().GetAwaiter().GetResult(); } /// @@ -97,14 +93,23 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine /// 如果可以切换则返回true,否则返回false public async Task CanChangeToAsync() 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(); + } } + /// /// 切换到指定类型的状态 /// @@ -113,22 +118,10 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine /// 当目标状态未注册时抛出 public bool ChangeTo() 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().GetAwaiter().GetResult(); } + /// /// 异步切换到指定类型的状态 /// @@ -137,30 +130,37 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine /// 当目标状态未注册时抛出 public async Task ChangeToAsync() 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(); + } } /// @@ -222,11 +222,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine /// 如果成功回退则返回true,否则返回false public bool GoBack() { - var previousState = FindValidPreviousState(); - if (previousState == null) return false; - - ChangeInternalWithoutHistory(previousState); - return true; + return GoBackAsync().GetAwaiter().GetResult(); } /// @@ -235,11 +231,19 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine /// 如果成功回退则返回true,否则返回false public async Task 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(); + } } /// @@ -310,24 +314,6 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine } } - /// - /// 内部状态切换方法(不记录历史),用于回退操作 - /// - /// 下一个状态实例 - 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); - } - /// /// 异步内部状态切换方法(不记录历史),用于回退操作 /// @@ -346,32 +332,6 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine await OnStateChangedAsync(old, Current); } - /// - /// 内部状态切换方法,处理状态切换的核心逻辑 - /// - /// 下一个状态实例 - 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); - } - /// /// 异步内部状态切换方法,处理状态切换的核心逻辑 /// @@ -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); } diff --git a/GFramework.Core/state/StateMachineSystem.cs b/GFramework.Core/state/StateMachineSystem.cs index 6bed3bb..1fbab8e 100644 --- a/GFramework.Core/state/StateMachineSystem.cs +++ b/GFramework.Core/state/StateMachineSystem.cs @@ -71,22 +71,6 @@ public class StateMachineSystem : StateMachine, IStateMachineSystem States.Clear(); } - /// - /// 内部状态切换方法,重写基类方法以添加状态变更事件通知功能 - /// - /// 要切换到的下一个状态 - protected override void ChangeInternal(IState next) - { - var old = Current; - base.ChangeInternal(next); - - // 发送状态变更事件,通知监听者状态已发生改变 - this.SendEvent(new StateChangedEvent - { - OldState = old, - NewState = Current - }); - } /// /// 异步内部状态切换方法,重写基类方法以添加状态变更事件通知功能