指令等待模型

a. 单等待模型

用于需要等待某事件的响应或定时等待。在等待时间比较长的时候可考虑使用。

  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 }
View Code

b. 多等待模型

用于需要在短时间等待若干事件的响应进行后续操作的情况。

 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 }
View Code
  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 }
View Code

有些时候,比如客户端使用udp向服务端发送命令后,要求客户端在一段时间内没接收到服务端应答时进行重发操作,可以考虑a模型;a模型也可以用作一个闹钟。上述模型避免了外部类注册回调或事件,提供了类间的松散耦合。

 

posted @ 2020-03-29 19:41  不会吉他的程序员  阅读(209)  评论(0编辑  收藏  举报