1 /// <summary> 2 /// 耗时计数器 3 /// </summary> 4 public class ElapsedTimer 5 { 6 // 创建时默认为创建时间,这样不调用 Start 也可以 7 private DateTime _StartTime = DateTime.Now; 8 9 // 计时开始 10 public void Start() 11 { 12 _StartTime = DateTime.Now; 13 } 14 15 // 计时结束(输出毫秒) 16 public long Over() 17 { 18 var timespan = DateTime.Now - _StartTime; 19 return Convert.ToInt32(timespan.TotalMilliseconds); 20 } 21 22 // 取得间隔 23 public TimeSpan Span() 24 { 25 return DateTime.Now - _StartTime; 26 } 27 28 /// <summary> 29 /// 静态方法,运行指定函数,返回耗时结果 30 /// </summary> 31 /// <param name="action"></param> 32 /// <returns></returns> 33 public static TimeSpan Elapsed(Action action) 34 { 35 ElapsedTimer tcc = new ElapsedTimer(); 36 action(); 37 return tcc.Span(); 38 } 39 }
1 public class QueueTask<T> 2 { 3 // 对象标识 4 public T ObjectKey { get; set; } 5 6 // 回调方法 7 public Action<T, String> Callback { get; set; } 8 9 /// <summary> 10 /// 用于保存一些回调时使用的上下文信息 11 /// </summary> 12 public string Context { get; set; } 13 }
1 public class QueueTaskRunner<T> 2 { 3 // 任务队列,由任务运行线程逐个执行 4 private Queue<QueueTask<T>> _TaskRunQueue = new Queue<QueueTask<T>>(); 5 // 用来同步操作任务队列,使得线程安全(生产者,消费者模式) 6 private object _RunLocker = new object(); 7 8 // 超时任务执行线程 9 private Thread _TaskRunThread; 10 // 用于同步操作任务队列的线程信号(生产者,消费者通知作用) 11 private EventWaitHandle _WaitHandle = new AutoResetEvent(false); 12 // 用于退出执行线程的一个标识 13 private bool _Working = true; 14 15 /// <summary> 16 /// 创建实例时,开启:任务执行线程 17 /// </summary> 18 public QueueTaskRunner() 19 { 20 _TaskRunThread = new Thread(new ThreadStart(TaskRunning)); 21 _TaskRunThread.Start(); 22 } 23 24 /// <summary> 25 /// 任务执行线程主体 26 /// </summary> 27 private void TaskRunning() 28 { 29 while (_Working) 30 { 31 QueueTask<T> task = null; 32 lock (_RunLocker) 33 { 34 if (_TaskRunQueue.Count > 0) 35 { 36 task = _TaskRunQueue.Dequeue(); 37 } 38 } 39 // 存在超时任务执行其回调 40 if (task != null) 41 { 42 task.Callback(task.ObjectKey, task.Context); 43 } 44 else 45 { 46 // 等待生产者通知 47 _WaitHandle.WaitOne(); 48 } 49 } 50 } 51 52 #region 以下为向外开放的功能 53 54 /// <summary> 55 /// 添加任务 56 /// </summary> 57 /// <param name="objectKey"></param> 58 /// <param name="callback"></param> 59 public void AddTask(T objectKey, Action<T, String> callback) 60 { 61 AddTask(objectKey, callback, null); 62 } 63 64 /// <summary> 65 /// 添加任务 66 /// </summary> 67 /// <param name="objectKey"></param> 68 /// <param name="callback"></param> 69 /// <param name="context"></param> 70 public void AddTask(T objectKey, Action<T, String> callback, String context) 71 { 72 QueueTask<T> task = new QueueTask<T>(); 73 task.ObjectKey = objectKey; 74 task.Callback = callback; 75 task.Context = context; 76 77 // 加入任务执行队列 78 lock (_RunLocker) 79 { 80 _TaskRunQueue.Enqueue(task); 81 } 82 // 有生产,则通知执行线程(消费者) 83 _WaitHandle.Set(); 84 } 85 86 /// <summary> 87 /// 销毁时,退出线程执行体,释放内存 88 /// </summary> 89 public void Dispose() 90 { 91 _Working = false; 92 _WaitHandle.Set(); 93 _TaskRunThread.Join(); 94 _WaitHandle.Close(); 95 } 96 97 #endregion 98 99 }
1 /// <summary> 2 /// 超时回调的委托 3 /// </summary> 4 /// <typeparam name="T"></typeparam> 5 /// <param name="objectKey"></param> 6 /// <param name="context"></param> 7 public delegate void TimeoutCallback<T>(T objectKey, String context); 8 9 /// <summary> 10 /// 超时任务信息 11 /// </summary> 12 /// <typeparam name="T"></typeparam> 13 public class TimeoutTask<T> 14 { 15 // 任务标识(由超时任务运行器自动分配) 16 public long TaskId { get; set; } 17 // 对象标识 18 public T ObjectKey { get; set; } 19 // 超时秒数 20 public int TimeoutSeconds { get; set; } 21 /// <summary> 22 /// 以秒为单位的 Tick 值,由超时任务运行器根据当前时间加上超时秒数计算设置 23 /// DateTime.Ticks 是以 10ns(10纳秒) 为单位 24 /// 将其除以 10 单位为 ws(微秒),再除以 1000 为 ms(毫秒),再除以 1000 为 s(秒) 25 /// 累计为 DateTime.Ticks / 10000000 26 /// </summary> 27 public long ExecuteSecondTicks { get; set; } 28 // 超时回调方法 29 public TimeoutCallback<T> Callback { get; set; } 30 /// <summary> 31 /// 用于保存一些回调时使用的上下文信息 32 /// </summary> 33 public String Context { get; set; } 34 }
1 /// <summary> 2 /// 超时任务运行器 3 /// 专为超时时间到达后执行的任务,在超时时间到达之间,可以随时移除 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 public class TimeoutTaskRunner<T> 7 { 8 // 为添加的超时任务分配的 TaskId 任务标识序列 9 private long _TaskIdSequence = 0; 10 11 // 超时检测者,每秒扫描是否达到超时,超时则加入超时任务队列 12 private System.Timers.Timer _TimeoutChecker = new System.Timers.Timer(); 13 14 // 以 TaskId(任务标识) 为 KEY 的任务清单字典 15 private Dictionary<long, TimeoutTask<T>> _TaskIdDictionary = new Dictionary<long, TimeoutTask<T>>(); 16 // 以 ObjectId(任务相关对象标识) 为 KEY 的任务字典,因每个对象可以有多个超时任务,所以为列表 17 private Dictionary<T, List<TimeoutTask<T>>> _TaskObjectKeyDictionary = new Dictionary<T, List<TimeoutTask<T>>>(); 18 // 用于同步操作上述两个清单字典,使得线程安全 19 private object _DictionaryLocker = new object(); 20 21 // 已超时任务队列,由任务运行线程逐个执行 22 private Queue<TimeoutTask<T>> _TaskRunQueue = new Queue<TimeoutTask<T>>(); 23 // 用来同步操作任务队列,使得线程安全(生产者,消费者模式) 24 private object _RunLocker = new object(); 25 26 // 超时任务执行线程 27 private Thread _TaskRunThread; 28 // 用于同步操作任务队列的线程信号(生产者,消费者通知作用) 29 private EventWaitHandle _WaitHandle = new AutoResetEvent(false); 30 // 用于退出执行线程的一个标识 31 private bool _Working = true; 32 33 34 /// <summary> 35 /// 创建实例时,开启:(1)超时检测者 (2)超时任务执行线程 36 /// </summary> 37 public TimeoutTaskRunner() 38 { 39 // (1)超时检测者 40 _TimeoutChecker.Interval = 1000; 41 _TimeoutChecker.Elapsed += new System.Timers.ElapsedEventHandler(CheckTimerTick); 42 _TimeoutChecker.Start(); 43 44 // (2)超时任务执行线程 45 _TaskRunThread = new Thread(new ThreadStart(TaskRunning)); 46 _TaskRunThread.Start(); 47 } 48 49 /// <summary> 50 /// 超时任务检测者 51 /// 对于,时间已经超过了设定的超时时间的,加入超时任务执行队列 52 /// </summary> 53 /// <param name="sender"></param> 54 /// <param name="e"></param> 55 private void CheckTimerTick(object sender, System.Timers.ElapsedEventArgs e) 56 { 57 long secondTicks = DateTime.Now.Ticks / 10000000; 58 // 遍历,把时间已到达超过超时时间的找出来 59 lock (_DictionaryLocker) 60 { 61 foreach (var key in _TaskIdDictionary.Keys.ToList()) 62 { 63 var task = _TaskIdDictionary[key]; 64 if (_TaskIdDictionary[key].ExecuteSecondTicks <= secondTicks) 65 { 66 // 加入超时任务执行队列,并移除清单 67 lock (_RunLocker) 68 { 69 _TaskRunQueue.Enqueue(task); 70 RemoveTimeoutTask(task.TaskId); 71 } 72 // 有生产,则通知执行线程(消费者) 73 _WaitHandle.Set(); 74 } 75 } 76 } 77 } 78 79 /// <summary> 80 /// 超时任务执行线程主体 81 /// </summary> 82 private void TaskRunning() 83 { 84 while (_Working) 85 { 86 TimeoutTask<T> task = null; 87 lock (_RunLocker) 88 { 89 if (_TaskRunQueue.Count > 0) 90 { 91 task = _TaskRunQueue.Dequeue(); 92 } 93 } 94 // 存在超时任务执行其回调 95 if (task != null) 96 { 97 task.Callback(task.ObjectKey, task.Context); 98 } 99 else 100 { 101 // 等待生产者通知 102 _WaitHandle.WaitOne(); 103 } 104 } 105 } 106 107 /// <summary> 108 /// 获取下一个任务标识 109 /// </summary> 110 /// <returns></returns> 111 [MethodImplAttribute(MethodImplOptions.Synchronized)] 112 private long GetNextTaskId() 113 { 114 _TaskIdSequence = (_TaskIdSequence + 1) % long.MaxValue; 115 return _TaskIdSequence; 116 } 117 118 #region 以下为向外开放的功能 119 120 public long AddTimeoutTask(T objectKey, int timeoutSeconds, TimeoutCallback<T> callback) 121 { 122 return AddTimeoutTask(objectKey, timeoutSeconds, callback, null); 123 } 124 125 /// <summary> 126 /// 指定对象标识,超时时长(秒为单位),超时执行回调,加入到超时检测字典中 127 /// </summary> 128 /// <param name="objectKey"></param> 129 /// <param name="timeoutSeconds"></param> 130 /// <param name="callback"></param> 131 /// <param name="context"></param> 132 /// <returns></returns> 133 public long AddTimeoutTask(T objectKey, int timeoutSeconds, TimeoutCallback<T> callback, String context) 134 { 135 TimeoutTask<T> task = new TimeoutTask<T>(); 136 task.ObjectKey = objectKey; 137 task.TimeoutSeconds = timeoutSeconds; 138 task.Callback = callback; 139 long taskId = GetNextTaskId(); 140 task.TaskId = taskId; 141 task.ExecuteSecondTicks = DateTime.Now.Ticks / 10000000 + timeoutSeconds; 142 task.Context = context; 143 144 lock (_DictionaryLocker) 145 { 146 // 以任务标识为主键的任务清单 147 _TaskIdDictionary[taskId] = task; 148 // 以对象标识为主键的任务清单 149 if (_TaskObjectKeyDictionary.ContainsKey(objectKey)) 150 { 151 _TaskObjectKeyDictionary[objectKey].Add(task); 152 } 153 else 154 { 155 List<TimeoutTask<T>> list = new List<TimeoutTask<T>>(); 156 list.Add(task); 157 _TaskObjectKeyDictionary[objectKey] = list; 158 } 159 } 160 return taskId; 161 } 162 163 /// <summary> 164 /// 根据对象标识移除超时任务设置 165 /// </summary> 166 /// <param name="objectKey"></param> 167 public void RemoveTimeoutTask(T objectKey) 168 { 169 lock (_DictionaryLocker) 170 { 171 if (_TaskObjectKeyDictionary.ContainsKey(objectKey)) 172 { 173 // 在任务标识为主键的清单中移除相应的该对象的多个超时任务 174 foreach (var task in _TaskObjectKeyDictionary[objectKey]) 175 { 176 _TaskIdDictionary.Remove(task.TaskId); 177 } 178 _TaskObjectKeyDictionary[objectKey].Clear(); 179 } 180 } 181 } 182 183 /// <summary> 184 /// 根据任务标识移除超时任务设置 185 /// </summary> 186 /// <param name="taskId"></param> 187 public void RemoveTimeoutTask(long taskId) 188 { 189 lock (_DictionaryLocker) 190 { 191 if (_TaskIdDictionary.ContainsKey(taskId)) 192 { 193 var task = _TaskIdDictionary[taskId]; 194 _TaskIdDictionary.Remove(taskId); 195 // 在对象标识为主键的清单移除相应的超时任务 196 _TaskObjectKeyDictionary[task.ObjectKey].Remove(task); 197 } 198 } 199 } 200 201 /// <summary> 202 /// 销毁时,退出线程执行体,释放内存 203 /// </summary> 204 public void Dispose() 205 { 206 _Working = false; 207 _WaitHandle.Set(); 208 _TaskRunThread.Join(100); 209 _WaitHandle.Close(); 210 } 211 212 #endregion 213 214 }