namespace MeloongCore; public interface IWorker { /// 在工作线程运行工作负载。 void Start(CancellationToken cancellationToken = default, ProgressProvider? progressOverride = null); /// 取消当前运行。 void Cancel(); /// 若当前正在运行中,等待其完成。若未在运行中,则立即返回。 /// 若未超时则返回 true。 bool WaitIfRunning(int millisecondsTimeout = -1, CancellationToken cancellationToken = default); /// 若当前正在运行中,异步等待其完成。若未在运行中,则立即返回。 /// 若未超时则返回 true。 Task WaitIfRunningAsync(int millisecondsTimeout = -1, CancellationToken cancellationToken = default); /// 从空闲状态进入运行状态时触发。 event Action? Started; /// 运行结束并进入空闲状态时触发。 event Action? Stopped; /// 工作负载成功完成时触发。 public event Action? Succeeded; /// 工作负载执行失败时触发,参数为发生的异常。 public event Action? Failed; /// 运行被取消时触发。 event Action? Canceled; /// 当前是否正在运行。 bool Running { get; } /// 是否曾经有过未被取消且未失败的运行。 bool HasSucceeded { get; } /// 标识上次进入空闲时,并非因为取消或失败,而是正常运行到结束。 bool LastSucceeded { get; } /// 当前工作负载的执行进度。 ProgressProvider Progress { get; } } /// /// 可合并和重启的工作器。 /// 在工作负载运行期间多次调用 会取消当前负载并使用最新令牌重新执行;多次调用也只重新执行一次。 /// public abstract class RedoableWorkerBase(Func workload, ProgressProvider? progress = null, [CallerMemberName] string creatorMemberName = "") : IWorker { // ============================================ 状态与事件 ============================================ /// public bool Running { get { lock (this) return running; } } private bool running; /// public event Action? Started; /// public event Action? Stopped; /// public bool HasSucceeded { get { lock (this) return hasSucceeded; } } private bool hasSucceeded; /// public event Action? Succeeded; /// public event Action? Failed; /// public event Action? Canceled; /// public bool LastSucceeded { get { lock (this) return lastSucceeded; } } private bool lastSucceeded; /// 上次未被取消且未失败的运行中,工作负载的返回值。 public TOut LastResult { get { lock (this) { if (typeof(TOut) == typeof(NoType)) throw new InvalidOperationException("该 Worker 没有返回值。"); if (!hasSucceeded) throw new InvalidOperationException("从未成功完成过。"); return lastResult == null ? default! : (TOut) lastResult; } } } private object? lastResult; /// public ProgressProvider Progress { get; private set; } = progress ?? new ProgressProvider(); private bool pendingRedo; // =========================================== 运行与取消 =========================================== private CancellationTokenSource? realCts; private CancellationToken lastToken; private readonly ManualResetEventSlim idleEvent = new(initialState: true); /// 在工作线程运行工作负载。若当前已在运行,则取消当前负载并使用最新令牌重启。 public void Start(CancellationToken cancellationToken = default, ProgressProvider? progressOverride = null) { // 接取运行状态 lock (this) { lastToken = cancellationToken; if (progressOverride != null) Progress = progressOverride; if (running) { Logger.Info($"{creatorMemberName}:接到重启请求"); pendingRedo = true; realCts?.Cancel(); return; } running = true; idleEvent.Reset(); realCts = CancellationTokenSource.CreateLinkedTokenSource(lastToken); } var th = new Thread(_Start) { IsBackground = true, Name = $"W/{creatorMemberName}" }; th.Start(); } private void _Start() { Logger.Info($"{creatorMemberName}:运行开始"); Started?.Invoke(); while (true) { try { realCts!.Token.ThrowIfCancellationRequested(); Progress?.Reset(); TOut result = workload(realCts.Token, Progress); // 实际的执行 realCts.Token.ThrowIfCancellationRequested(); lock (this) { realCts?.Dispose(); if (pendingRedo) { // 接取重启请求 pendingRedo = false; realCts = CancellationTokenSource.CreateLinkedTokenSource(lastToken); continue; } realCts = null; lastSucceeded = true; lastResult = result; hasSucceeded = true; running = false; idleEvent.Set(); Progress?.Finish(); } Logger.Info($"{creatorMemberName}:运行成功"); Succeeded?.Invoke(); } catch (Exception ex) { if (!ex.IsCanceled()) Logger.Log(ex, $"{creatorMemberName}:运行失败{(pendingRedo ? ",但即将重启,或可忽略" : "")}", pendingRedo ? LogLevel.Warn : LogLevel.Error, LogBehavior.ToastIfDebug); lock (this) { realCts?.Dispose(); if (pendingRedo) { // 接取重启请求 Logger.Info($"{creatorMemberName}:重启开始"); pendingRedo = false; realCts = CancellationTokenSource.CreateLinkedTokenSource(lastToken); continue; } realCts = null; lastSucceeded = false; running = false; idleEvent.Set(); Progress?.Skip(); } if (ex.IsCanceled()) { Logger.Info($"{creatorMemberName}:运行已取消"); Canceled?.Invoke(); } else { Failed?.Invoke(ex); } } break; } Stopped?.Invoke(); } /// public void Cancel() { lock (this) { pendingRedo = false; Logger.Info($"{creatorMemberName}:接到取消请求"); realCts?.Cancel(); } } /// public bool WaitIfRunning(int millisecondsTimeout = -1, CancellationToken cancellationToken = default) => idleEvent.Wait(millisecondsTimeout, cancellationToken); /// public async Task WaitIfRunningAsync(int millisecondsTimeout = -1, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var waitHandle = ThreadPool.RegisterWaitForSingleObject(idleEvent.WaitHandle, (_, timedOut) => completionSource.TrySetResult(!timedOut), null, millisecondsTimeout, executeOnlyOnce: true); using var cancellationRegistration = cancellationToken.Register(() => completionSource.TrySetCanceled(cancellationToken)); try { return await completionSource.Task.NoCapture(); } finally { waitHandle.Unregister(null); } } } /// public class RedoableWorker : RedoableWorkerBase { public RedoableWorker(Func workload, [CallerMemberName] string creatorMemberName = "") : base(workload, creatorMemberName: creatorMemberName) { } public RedoableWorker(Func workload, [CallerMemberName] string creatorMemberName = "") : base((c, _) => workload(c), creatorMemberName: creatorMemberName) { } public RedoableWorker(Func workload, [CallerMemberName] string creatorMemberName = "") : base((_, _) => workload(), creatorMemberName: creatorMemberName) { } } /// public class RedoableWorker : RedoableWorkerBase { public RedoableWorker(Action workload, [CallerMemberName] string creatorMemberName = "") : base((c, p) => { workload(c, p); return null; }, creatorMemberName: creatorMemberName) { } public RedoableWorker(Action workload, [CallerMemberName] string creatorMemberName = "") : base((c, _) => { workload(c); return null; }, creatorMemberName: creatorMemberName) { } public RedoableWorker(Action workload, [CallerMemberName] string creatorMemberName = "") : base((_, _) => { workload(); return null; }, creatorMemberName: creatorMemberName) { } } /// 指示没有该类型,用于泛型参数。 public class NoType { }