using System; using System.Threading; using System.Threading.Tasks; namespace XP.Common.Controls.ImageHistogram { /// /// 帧率限流器,确保计算频率不超过 MaxFrameRate | Frame rate throttler /// 支持从任意线程调用,使用 lock 保护内部状态 /// internal sealed class FrameThrottler : IDisposable { private readonly object _lock = new(); private DateTime _lastProcessTime = DateTime.MinValue; private Action? _pendingAction; private CancellationTokenSource? _delayCts; private bool _isProcessing; private bool _disposed; private int _maxFrameRate = 15; /// /// 最大刷新帧率(fps),有效范围 1-60,超出范围自动钳位 | Max frame rate (fps), valid range 1-60, auto-clamped /// public int MaxFrameRate { get => _maxFrameRate; set => _maxFrameRate = Math.Clamp(value, 1, 60); } /// /// 获取当前帧间隔(毫秒)| Get current frame interval (ms) /// private double FrameIntervalMs => 1000.0 / _maxFrameRate; /// /// 提交一帧计算动作 | Submit a frame compute action /// 若未超过帧率限制则立即执行,否则缓存最新帧并延迟触发 /// /// 计算动作 | Compute action /// 是否被立即接受处理 | Whether it was immediately accepted public bool TrySubmit(Action computeAction) { if (_disposed || computeAction == null) return false; lock (_lock) { var now = DateTime.UtcNow; var elapsed = (now - _lastProcessTime).TotalMilliseconds; if (elapsed >= FrameIntervalMs && !_isProcessing) { // 已超过间隔且无正在处理的任务,立即执行 | Interval exceeded and no processing, execute immediately _isProcessing = true; _lastProcessTime = now; ExecuteAction(computeAction); return true; } else { // 未超过间隔或正在处理中,缓存最新帧(丢弃之前的中间帧)| Cache latest frame, discard previous _pendingAction = computeAction; ScheduleDelayedExecution(elapsed); return false; } } } /// /// 执行计算动作(异步,完成后检查待处理帧)| Execute compute action asynchronously /// private void ExecuteAction(Action action) { Task.Run(() => { try { action.Invoke(); } catch { // 异常不外抛 | Do not propagate exceptions } finally { OnActionCompleted(); } }); } /// /// 计算动作完成后的回调 | Callback after compute action completes /// private void OnActionCompleted() { Action? nextAction = null; lock (_lock) { _isProcessing = false; if (_pendingAction != null && !_disposed) { var now = DateTime.UtcNow; var elapsed = (now - _lastProcessTime).TotalMilliseconds; if (elapsed >= FrameIntervalMs) { // 间隔已到,立即执行待处理帧 | Interval reached, execute pending frame nextAction = _pendingAction; _pendingAction = null; _isProcessing = true; _lastProcessTime = now; } // 否则等待延迟触发 | Otherwise wait for delayed trigger } } if (nextAction != null) { ExecuteAction(nextAction); } } /// /// 安排延迟执行(等待帧间隔到期后处理最新帧)| Schedule delayed execution /// private void ScheduleDelayedExecution(double elapsedMs) { // 取消之前的延迟任务 | Cancel previous delay task _delayCts?.Cancel(); _delayCts?.Dispose(); _delayCts = new CancellationTokenSource(); var token = _delayCts.Token; var delayMs = Math.Max(0, FrameIntervalMs - elapsedMs); Task.Run(async () => { try { await Task.Delay((int)delayMs, token); if (token.IsCancellationRequested) return; Action? actionToExecute = null; lock (_lock) { if (_pendingAction != null && !_isProcessing && !_disposed) { actionToExecute = _pendingAction; _pendingAction = null; _isProcessing = true; _lastProcessTime = DateTime.UtcNow; } } if (actionToExecute != null) { ExecuteAction(actionToExecute); } } catch (OperationCanceledException) { // 延迟被取消,正常情况 | Delay cancelled, normal case } catch { // 异常不外抛 | Do not propagate exceptions } }); } /// /// 取消所有待处理任务 | Cancel all pending tasks /// public void Cancel() { lock (_lock) { _pendingAction = null; _delayCts?.Cancel(); _delayCts?.Dispose(); _delayCts = null; } } /// /// 释放所有资源 | Dispose all resources /// public void Dispose() { if (_disposed) return; _disposed = true; lock (_lock) { _pendingAction = null; _delayCts?.Cancel(); _delayCts?.Dispose(); _delayCts = null; } } } }