1 核心设计
using System;
using System.Collections.Concurrent;
using System.Timers;namespace PriorityTimerManager;public sealed class PriorityTimerManager : IDisposable
{public sealed class OperationContext{private OperationContext(string tag, int periodMs){Tag = tag;PeriodMs = periodMs;}public string Tag { get; } = "";public int PeriodMs { get; }public static OperationContext Create(string tag, int periodMs){if (string.IsNullOrEmpty(tag)){throw new ArgumentException("Tag cannot be null or empty.", nameof(tag));}if (periodMs <= 0){throw new ArgumentOutOfRangeException(nameof(periodMs), "Period must be greater than zero.");}return new OperationContext(tag, periodMs);}}private sealed class Candidate{private Candidate(int periodMs, int basePriority, int strength, DateTime now, string tag, Action action){PeriodMs = periodMs;BasePriority = basePriority;Strength = strength;Arrival = now;SourceTag = tag;Execute = action;}public int PeriodMs { get; }public int BasePriority { get; } // 数字越小优先级越高public int Strength { get; } // 数字越小优先级越高public DateTime Arrival { get; }public string SourceTag { get; } = "";public Action Execute { get; } = () => { };public static Candidate Create(int periodMs, int basePriority, int strength, DateTime now, string tag, Action action){if (string.IsNullOrEmpty(tag)){throw new ArgumentException("Tag cannot be null or empty.", nameof(tag));}if (periodMs <= 0){throw new ArgumentOutOfRangeException(nameof(periodMs), "Period must be greater than zero.");}if (basePriority < 0){throw new ArgumentOutOfRangeException(nameof(basePriority), "Base priority must be non-negative.");}if (strength < 0){throw new ArgumentOutOfRangeException(nameof(strength), "Strength must be non-negative.");}return new Candidate(periodMs, basePriority, strength, now, tag, action);}}private sealed class CycleState{public readonly object LockObj = new();public Candidate? CurrentWinner;public Timer ResetTimer;private CycleState(Timer resetTimer){ResetTimer = resetTimer;}public static CycleState Create(Timer resetTimer){if (resetTimer == null){throw new ArgumentNullException(nameof(resetTimer), "Timer cannot be null.");}return new CycleState(resetTimer);}}private readonly ConcurrentDictionary<int, CycleState> _cycleStates = new();/// <summary>/// 决定操作强度的策略函数(可外部替换)/// </summary>public Func<OperationContext, int> StrengthStrategy { get; set; } = ctx => 100; // 默认所有操作强度=100(最弱)/// <summary>/// 注册一个优先级定时器/// </summary>/// <param name="periodMs"></param>/// <param name="basePriority"></param>/// <param name="tag"></param>/// <param name="action"></param>/// <returns></returns>public Timer RegisterTimer(int periodMs, int basePriority, string tag, Action action){// 确保该周期有对应状态var cs = _cycleStates.GetOrAdd(periodMs, p =>{var resetTimer = new Timer(p);var state = CycleState.Create(resetTimer);resetTimer.AutoReset = true;resetTimer.Elapsed += (s, e) => ResetCycle(state, p);resetTimer.Start();return state;});// 用户任务定时器var t = new Timer(periodMs){AutoReset = true};t.Elapsed += (s, e) =>{var strength = StrengthStrategy(OperationContext.Create(tag, periodMs));var c = Candidate.Create(periodMs, basePriority, strength, DateTime.Now, tag, action);OnTimerFired(cs, c);};t.Start();return t;}private void OnTimerFired(CycleState cs, Candidate c){lock (cs.LockObj){if (cs.CurrentWinner == null){cs.CurrentWinner = c;Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 初次执行: {c.SourceTag}");c.Execute();return;}var cur = cs.CurrentWinner;bool shouldPreempt = (c.Strength < cur.Strength) ||(c.Strength == cur.Strength && c.BasePriority < cur.BasePriority) ||(c.Strength == cur.Strength && c.BasePriority == cur.BasePriority &&c.Arrival < cur.Arrival);if (shouldPreempt){Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 抢占: {c.SourceTag} 覆盖 {cur.SourceTag}");cs.CurrentWinner = c;c.Execute();}else{Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] 忽略: {c.SourceTag} (被 {cur.SourceTag} 压制)");}}}private static void ResetCycle(CycleState state, int periodMs){lock (state.LockObj){state.CurrentWinner = null;Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] ===== 新周期开始 ({periodMs}ms) =====");}}public void Dispose(){foreach (var kv in _cycleStates){kv.Value.ResetTimer.Dispose();}}
}
2 使用
using System;namespace PriorityTimerManager;class Program
{static void Main(){using var manager = new PriorityTimerManager();// 配置强度策略manager.StrengthStrategy = ctx =>{return ctx.Tag switch{"写0" => 0, // 最强"写1" => 5,"写2" => 10,"写X" => 50,_ => 100 // 默认最弱};};// 6 秒周期任务manager.RegisterTimer(6000, basePriority: 2, tag: "写1", () => Console.WriteLine("执行: 写 1"));manager.RegisterTimer(6000, basePriority: 1, tag: "写0", () => Console.WriteLine("执行: 写 0"));manager.RegisterTimer(6000, basePriority: 3, tag: "写2", () => Console.WriteLine("执行: 写 2"));// 10 秒周期任务manager.RegisterTimer(10000, basePriority: 2, tag: "写X", () => Console.WriteLine("执行: 写 X"));manager.RegisterTimer(10000, basePriority: 1, tag: "写0_10s", () => Console.WriteLine("执行: 写 0 (10s)"));Console.WriteLine("定时器运行中,按任意键退出...");Console.ReadKey();}
}