指令等待模型
a. 单等待模型
用于需要等待某事件的响应或定时等待。在等待时间比较长的时候可考虑使用。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Threading; 3 4 namespace Hu.Tools.Algorithm 5 { 6 public abstract class TimeoutHandler : IDisposable 7 { 8 AutoResetEvent _auto = new AutoResetEvent(false); 9 10 public bool IsWaiting 11 { 12 get { return _isWaiting; } 13 } 14 private volatile bool _isWaiting = false; 15 16 public int Timeout 17 { 18 get { return _timeout; } 19 set 20 { 21 if (value < 0 && value != -1) 22 throw new ArgumentException("值必须为小于int.MaxValue的非负数或为-1"); 23 24 _timeout = value; 25 } 26 } 27 protected int _timeout; 28 29 /// <summary> 30 /// 当前等待指定的状态对象,其与方法<see cref="OnWaitCompleted(object)"/>和 31 /// <see cref="OnWaitTimeout(object)"/>中的状态有所区别,本对象始终为指向最 32 /// 新等待指定的状态的引用,或为空(当前没有在执行的等待)。 33 /// </summary> 34 public object RunningState 35 { 36 get { return _runningState; } 37 } 38 private object _runningState; 39 40 public TimeoutHandler() 41 : this(10000) 42 { } 43 44 public TimeoutHandler(int timeoutms) 45 { 46 _timeout = timeoutms; 47 } 48 49 ~TimeoutHandler() 50 { 51 if (_auto != null) 52 _auto.Dispose(); 53 } 54 55 public void DoWait(object state = null) 56 { 57 if (true == IsWaiting) 58 throw new InvalidOperationException($"当前等待未结束:{RunningState?.ToString()}"); 59 60 _isWaiting = true; 61 _runningState = state; 62 63 bool succeed = _auto.WaitOne(Timeout); 64 65 _isWaiting = false; 66 _runningState = null; 67 68 if (true == succeed) 69 OnWaitCompleted(state); 70 else 71 OnWaitTimeout(state); 72 } 73 74 public void DoWaitAsync(object state = null) 75 { 76 if (true == IsWaiting) 77 throw new InvalidOperationException($"当前等待未结束:{RunningState?.ToString()}"); 78 79 _isWaiting = true; 80 _runningState = state; 81 82 Func<bool> waitDel = Wait; 83 waitDel.BeginInvoke(ar => 84 { 85 Func<bool> del = ar.AsyncState as Func<bool>; 86 var succeed = del?.EndInvoke(ar); 87 88 _isWaiting = false; 89 _runningState = null; 90 91 if (true == succeed) 92 OnWaitCompleted(state); 93 else 94 OnWaitTimeout(state); 95 }, waitDel); 96 } 97 98 public void Dispose() 99 { 100 OnDispose(); 101 102 if (_auto != null) 103 _auto.Dispose(); 104 105 _auto = null; 106 } 107 108 protected abstract void OnWaitTimeout(object state); 109 110 protected virtual void OnWaitCompleted(object state) 111 { } 112 113 protected virtual void OnDispose() 114 { } 115 116 private bool Wait() 117 { 118 bool succeed = _auto.WaitOne(Timeout); 119 return succeed; 120 } 121 122 } 123 }
b. 多等待模型
用于需要在短时间等待若干事件的响应进行后续操作的情况。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading; 5 6 namespace Hu.Tools.Algorithm 7 { 8 public interface IModelOb<T> 9 { 10 void Deal(T data); 11 } 12 13 public interface ISubject<T> 14 { 15 bool Register(IModelOb<T> ob); 16 17 bool UnRegister(IModelOb<T> ob); 18 } 19 20 public class WaitModel<T> : ISubject<T>, IDisposable 21 { 22 Thread _thread; 23 Queue<T> _buffer; 24 AutoResetEvent _auto; 25 volatile bool _alive; 26 protected Action<T> _observers; 27 28 public WaitModel() 29 { 30 _alive = true; 31 _auto = new AutoResetEvent(false); 32 _buffer = new Queue<T>(); 33 _thread = new Thread(new ThreadStart(ThreadDistributeData)) { Name = "分发:" + typeof(T).ToString(), IsBackground = true }; 34 _thread.Start(); 35 } 36 37 public bool Register(IModelOb<T> ob) 38 { 39 _observers += ob.Deal; 40 return true; 41 } 42 43 public bool UnRegister(IModelOb<T> ob) 44 { 45 _observers -= ob.Deal; 46 return true; 47 } 48 49 public void Enqueue(T data) 50 { 51 if (false == _alive) 52 return; 53 54 _buffer.Enqueue(data); 55 _auto.Set(); 56 } 57 58 public void Dispose() 59 { 60 OnDispose(); 61 62 _alive = false; 63 _buffer.Clear(); 64 _auto.Dispose(); 65 _observers = null; 66 } 67 68 protected virtual void OnDispose() 69 { } 70 71 protected virtual void DistributeData(T data) 72 { 73 _observers?.Invoke(data); 74 } 75 76 private void ThreadDistributeData() 77 { 78 while (_alive) 79 { 80 if (_buffer.Count > 0) 81 { 82 try 83 { 84 T data = _buffer.Dequeue(); 85 if (data != null) 86 DistributeData(data); 87 } 88 catch (InvalidOperationException ioe) 89 { 90 Console.WriteLine(ioe.Message); 91 continue; 92 } 93 } 94 else 95 _auto.WaitOne(); 96 } 97 } 98 } 99 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading; 5 6 namespace Hu.Tools.Algorithm 7 { 8 [Remark("多线程环境(50 participants)测试通过<see ToolsTest.FTAlgorithm>")] 9 public abstract class MultiTimeoutHandler : WaitModel<Tuple<Delegate, object []>>, IModelOb<Tuple<Delegate, object[]>> 10 { 11 protected List<TaskInfo> _lstTaskInfo = new List<TaskInfo>(); 12 13 public MultiTimeoutHandler() 14 : base() 15 { 16 Register(this); 17 } 18 19 public void CeaseWait(string taskID) 20 { 21 if (string.IsNullOrEmpty(taskID)) 22 throw new ArgumentNullException("taskID"); 23 24 Action<string> op = DoCeaseWait; 25 Enqueue(new Tuple<Delegate, object[]>(op, new[] { taskID })); 26 } 27 28 private void DoCeaseWait(string taskID) 29 { 30 int idx = _lstTaskInfo.FindIndex(p => p.TaskID.CompareTo(taskID) == 0); 31 if (idx != -1) 32 { 33 _lstTaskInfo[idx].IsCanceled = true; 34 _lstTaskInfo.RemoveAt(idx); 35 } 36 } 37 38 public void WaitAsync(TaskInfo vTask) 39 { 40 Action<TaskInfo> op = DoWaitAsync; 41 Enqueue(new Tuple<Delegate, object[]>(op, new[] { vTask })); 42 } 43 44 private void DoWaitAsync(TaskInfo vTask) 45 { 46 var ti = _lstTaskInfo.FirstOrDefault(t => t.Equals(vTask)); 47 if (ti != null) 48 return; 49 50 _lstTaskInfo.Add(vTask); 51 52 Action<TaskInfo> waitDel = WaitTask; 53 waitDel.BeginInvoke(vTask, ar => 54 { 55 Action<TaskInfo> del = ar?.AsyncState as Action<TaskInfo>; 56 del?.EndInvoke(ar); 57 58 if (true == vTask.IsTimeout) 59 OnWaitTimeout(vTask); 60 else 61 OnWaitCompleted(vTask); 62 }, waitDel); 63 } 64 65 protected abstract void OnWaitTimeout(TaskInfo ti); 66 67 protected virtual void OnWaitCompleted(TaskInfo ti) 68 { } 69 70 protected virtual void WaitTask(TaskInfo ti) 71 { 72 DateTime st = DateTime.Now; 73 SpinWait sw = new SpinWait(); 74 while (false == ti.IsCanceled) 75 { 76 sw.SpinOnce(); 77 ti.IsTimeout = (DateTime.Now - st >= TimeSpan.FromMilliseconds(ti.Timeout)); 78 if (true == ti.IsTimeout) 79 break; 80 } 81 } 82 83 public void Deal(Tuple<Delegate, object[]> work) 84 { 85 work.Item1.DynamicInvoke(work.Item2); 86 } 87 88 } 89 90 public class TaskInfo : IEquatable<TaskInfo> 91 { 92 public string TaskID 93 { 94 get; 95 internal set; 96 } 97 98 public int Timeout 99 { 100 get; 101 internal set; 102 } 103 104 public bool IsTimeout 105 { 106 get; 107 internal set; 108 } 109 110 public bool IsCanceled 111 { 112 get; 113 internal set; 114 } 115 116 public TaskInfo(string vTaskID, int vTimeoutMs) 117 { 118 if (string.IsNullOrWhiteSpace(vTaskID)) 119 throw new ArgumentNullException("vTaskID"); 120 121 TaskID = vTaskID; 122 123 if (vTimeoutMs < 1) 124 throw new ArgumentException("vTimeoutMs必须为1到int.MaxValue间的数"); 125 126 Timeout = vTimeoutMs; 127 } 128 129 public bool Equals(TaskInfo other) 130 { 131 if (null == other) 132 return false; 133 134 return TaskID.CompareTo(other.TaskID) == 0; 135 } 136 137 public override bool Equals(object obj) 138 { 139 TaskInfo ti = obj as TaskInfo; 140 if (null == ti) 141 return false; 142 143 return TaskID.CompareTo(ti.TaskID) == 0; 144 } 145 146 public override int GetHashCode() 147 { 148 return base.GetHashCode(); 149 } 150 151 public override string ToString() 152 { 153 return $"TaskID:{TaskID}, Timeout:{Timeout}, IsCanceled:{IsCanceled}, IsTimeout:{IsTimeout}"; 154 } 155 } 156 }
有些时候,比如客户端使用udp向服务端发送命令后,要求客户端在一段时间内没接收到服务端应答时进行重发操作,可以考虑a模型;a模型也可以用作一个闹钟。上述模型避免了外部类注册回调或事件,提供了类间的松散耦合。
--I love this guy.