条件监视器

一、功能说明与定义

条件监视器:监测(循环判断)某一条件是否成立,成立则退出监测,备选条件,有监测总时间或总次数的限制。

二、产生背景

把文件从xps转成pdf的时候需要判断这份xps文件是否已经生成完成,且不被占用。由于xps生成的某种原因,生成完成xps时文件还处于占用状态,无法立即进行处理转换成pdf,在此前提下此功能与需求孕育而生。

三、实现

1、ConditionLooper.cs

  1     /// <summary>
  2     /// 条件循环器
  3     /// </summary>
  4     internal class ConditionLooper : IDisposable
  5     {
  6         /// <summary>
  7         /// 时间间隔,默认100毫秒(以毫秒为单位)
  8         /// </summary>
  9         public int Interval = 100;
 10         /// <summary>
 11         /// 首次调用是否延迟<see cref="Interval"/>指定的时间间隔,默认为<seealso cref="false"/>
 12         /// </summary>
 13         public bool IsFirstDelay = false;
 14         /// <summary>
 15         /// 是否正在运行
 16         /// </summary>
 17         public bool IsRunning = false;
 18         /// <summary>
 19         /// 超时时间(以毫秒为单位),默认为 -1 不启用
 20         /// </summary>
 21         public int TimeOut = -1;
 22         /// <summary>
 23         /// 循环执行次数,默认为 -1 不启用
 24         /// </summary>
 25         public int LoopTimes = -1;
 26         /// <summary>
 27         /// <see cref="WorkCheck"/>的执行结果,<seealso cref="ConditionLooperResult"/>类型枚举值。
 28         /// </summary>
 29         public ConditionLooperResult Result = ConditionLooperResult.None;
 30         /// <summary>
 31         /// 周期循环的检查任务,返回<see cref="true"/>时则会终止循环检测
 32         /// </summary>
 33         public event Func<bool> WorkCheck;
 34         /// <summary>
 35         /// 结束循环调用触发的事件
 36         /// </summary>
 37         public event Action<ConditionLooperResult> EndLoop;
 38         protected bool _enable;
 39         /// <summary>
 40         /// 启用/停用
 41         /// </summary>
 42         public virtual bool Enable
 43         {
 44             get
 45             {
 46                 return this._enable;
 47             }
 48             set
 49             {
 50                 if (this._enable != value)
 51                 {
 52                     this._enable = value;
 53                 }
 54 
 55                 if (this._enable)
 56                 {
 57                     this.Log($"{string.Format("{0,-4}", System.Threading.Thread.CurrentThread.ManagedThreadId)} -> 启动循环任务....");
 58                     this.Log($"{string.Format("{0,-4}", System.Threading.Thread.CurrentThread.ManagedThreadId)}Interval = {this.Interval},TimeOut = {this.TimeOut},LoopTimes = {this.LoopTimes},IsFirstDelay = {this.IsFirstDelay}");
 59                     this.Start((state) =>
 60                     {
 61                         //Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} -> ManagedThreadId = {System.Threading.Thread.CurrentThread.ManagedThreadId}.");
 62                         // 执行任务
 63                         var matched = (this.WorkCheck?.Invoke()).GetValueOrDefault(false);
 64                         if (matched)
 65                         {
 66                             // 满足条件,则终止
 67                             this.Log($"{string.Format("{0,-4}", System.Threading.Thread.CurrentThread.ManagedThreadId)} -> 满足条件终止。");
 68                             this.EndLoopInternal(ConditionLooperResult.Matched);
 69                             return;
 70                         }
 71 
 72                         // 启用超时设置时进行超时判断
 73                         if (this.IsEnableTimeOut)
 74                         {
 75                             this.Log($"{string.Format("{0,-4}", System.Threading.Thread.CurrentThread.ManagedThreadId)} -> ElapsedMilliseconds = {this.TotalTimeWatch.ElapsedMilliseconds}/{this.TimeOut}.");
 76                             if (this.TotalTimeWatch.ElapsedMilliseconds >= this.TimeOut)
 77                             {
 78                                 // 超时
 79                                 this.Log($"{string.Format("{0,-4}", System.Threading.Thread.CurrentThread.ManagedThreadId)} -> 超时退出。");
 80                                 this.EndLoopInternal(ConditionLooperResult.TimeOut);
 81                                 return;
 82                             }
 83                         }
 84 
 85                         if (this.IsEnableLoopTimes)
 86                         {
 87                             // 调用次数 +1
 88                             this.ExecuteTime++;
 89 
 90                             this.Log($"{string.Format("{0,-4}", System.Threading.Thread.CurrentThread.ManagedThreadId)} -> ExecuteTime = {this.ExecuteTime}/{this.LoopTimes}.");
 91                             if (this.ExecuteTime >= this.LoopTimes)
 92                             {
 93                                 // 超过次数限制
 94                                 this.Log($"{string.Format("{0,-4}", System.Threading.Thread.CurrentThread.ManagedThreadId)} -> 超过次数限制退出。");
 95                                 this.EndLoopInternal(ConditionLooperResult.TimesLimited);
 96                                 return;
 97                             }
 98                         }
 99                     });
100                 }
101                 else
102                 {
103                     this.Log($"{string.Format("{0,-4}", System.Threading.Thread.CurrentThread.ManagedThreadId)} -> 停止循环任务....");
104                     this.Stop();
105                 }
106             }
107         }
108 
109 
110         /// <summary>
111         /// 定时任务
112         /// </summary>
113         private System.Threading.Timer JobTimer;
114         /// <summary>
115         /// 总耗时计时器
116         /// </summary>
117         private Stopwatch TotalTimeWatch;
118         /// <summary>
119         /// 记录调用次数
120         /// </summary>
121         private int ExecuteTime = 0;
122         /// <summary>
123         /// 是否启用异步调用
124         /// </summary>
125         private bool IsAsyncCall = false;
126         /// <summary>
127         /// 等待信号,false - 默认等待;ture - 默认放行
128         /// </summary>
129         private AutoResetEvent WaitSignal = new AutoResetEvent(false);
130         /// <summary>
131         /// 判断是否启用超时时间设置
132         /// </summary>
133         private bool IsEnableTimeOut
134         {
135             get
136             {
137                 return (this.TimeOut > 0);
138             }
139         }
140         /// <summary>
141         /// 判断是否启用次数限制设置
142         /// </summary>
143         private bool IsEnableLoopTimes
144         {
145             get
146             {
147                 return (this.LoopTimes > 0);
148             }
149         }
150 
151         /// <summary>
152         /// 执行检查任务(同步调用)
153         /// </summary>
154         /// <param name="checker"></param>
155         /// <returns></returns>
156         public ConditionLooperResult Run(Func<bool> @checker)
157         {
158             this.IsAsyncCall = false;
159             this.WorkCheck = @checker;
160             this.Enable = true;
161 
162             // 等待放行信号
163             this.WaitSignal.WaitOne();
164 
165             return this.Result;
166         }
167         /// <summary>
168         /// 执行检查任务(异步调用)
169         /// </summary>
170         /// <param name="checker"></param>
171         /// <param name="callback"></param>
172         public void RunAsync(Func<bool> @checker, Action<ConditionLooperResult> callback)
173         {
174             this.IsAsyncCall = true;
175             this.WorkCheck = @checker;
176             this.EndLoop = callback;
177             this.Enable = true;
178         }
179         /// <summary>
180         /// 释放资源
181         /// </summary>
182         public virtual void Dispose()
183         {
184             // 停止计时器
185             this.StopTimer();
186 
187             if (null != this.WaitSignal)
188             {
189                 this.WaitSignal.Dispose();
190                 this.WaitSignal = null;
191             }
192         }
193 
194         /// <summary>
195         /// 停止计时器
196         /// </summary>
197         private void StopTimer()
198         {
199             if (null != this.JobTimer)
200             {
201                 this.JobTimer.Dispose();
202                 this.JobTimer = null;
203             }
204         }
205         /// <summary>
206         /// 停止任务
207         /// </summary>
208         protected virtual void Stop()
209         {
210             this.IsRunning = false;
211 
212             // 停止计时器
213             this.StopTimer();
214 
215             if (null != this.TotalTimeWatch)
216             {
217                 this.TotalTimeWatch.Stop();
218             }
219 
220             // 信号放行
221             if (!this.IsAsyncCall)
222             {
223                 this.WaitSignal.Set();
224             }
225         }
226         /// <summary>
227         /// 启动任务(创建并启动计时器)
228         /// </summary>
229         /// <param name="callback"></param>
230         protected virtual void Start(System.Threading.TimerCallback callback)
231         {
232             if ((null != this.JobTimer))
233             {
234                 // 停止计时器
235                 this.StopTimer();
236             }
237 
238             // 重置运行状态
239             this.Reset();
240             this.JobTimer = new System.Threading.Timer(callback, null, (this.IsFirstDelay ? this.Interval : 0), this.Interval);
241         }
242         /// <summary>
243         /// 重置运行状态
244         /// </summary>
245         protected virtual void Reset()
246         {
247             this.Result = ConditionLooperResult.None;
248 
249             if (!this.IsAsyncCall)
250             {
251                 // 设置为非终止,导致外部线程阻塞,等待任务完成或超时
252                 this.WaitSignal.Reset();
253             }
254 
255             if (this.IsEnableTimeOut)
256             {
257                 if (null == this.TotalTimeWatch)
258                 {
259                     this.TotalTimeWatch = new Stopwatch();
260                 }
261                 else
262                 {
263                     this.TotalTimeWatch.Reset();
264                 }
265 
266                 this.TotalTimeWatch.Start();
267             }
268 
269             if (this.IsEnableLoopTimes)
270             {
271                 this.ExecuteTime = 0;
272             }
273             this.IsRunning = true;
274         }
275         /// <summary>
276         /// 触发结束事件
277         /// </summary>
278         /// <param name="result">结果</param>
279         protected virtual void EndLoopInternal(ConditionLooperResult result)
280         {
281             // 保存结果
282             this.Result = result;
283             // 执行停止
284             this.Stop();
285 
286             // 触发结束事件
287             this.EndLoop?.Invoke(result);
288         }
289         /// <summary>
290         /// 记录日志
291         /// </summary>
292         /// <param name="content"></param>
293         [Conditional("DEBUG")]
294         protected virtual void Log(string content)
295         {
296             LogProvider.Log.Debug(content);
297 
298             //System.Diagnostics.Debug.WriteLine(content);
299             //Console.WriteLine(content);
300         }
301     }

2、ConditionLooperResult类

 1     /// <summary>
 2     /// 循环调用结果
 3     /// </summary>
 4     public enum ConditionLooperResult
 5     {
 6         /// <summary>
 7         /// 默认状态
 8         /// </summary>
 9         None = 0,
10         /// <summary>
11         /// 匹配
12         /// </summary>
13         Matched = 1,
14         /// <summary>
15         /// 超时
16         /// </summary>
17         TimeOut = 2,
18         /// <summary>
19         /// 超过次数限制
20         /// </summary>
21         TimesLimited = 3
22     }

3、ConditionMonitor类

 1     /// <summary>
 2     /// 条件监视器
 3     /// </summary>
 4     public static class ConditionMonitor
 5     {
 6         /// <summary>
 7         /// 周期性检测<paramref name="condition"/>条件表达式是否满足,直到满足条件或超时时间已到则退出。
 8         /// </summary>
 9         /// <param name="condition">条件表达式。</param>
10         /// <param name="interval">检测时间间隔,默认100毫秒。</param>
11         /// <param name="timeOut">检测超时时间,-1 为不启用,<paramref name="condition"/>表示的条件表达满足时才会退出。</param>
12         /// <param name="isDelay">首次调用是否延迟<paramref name="interval"/>指定的时间间隔,默认为<seealso cref="false"/></param>
13         /// <returns>检测结果</returns>
14         public static ConditionLooperResult Wait(Func<bool> condition, int interval = 100, int timeOut = -1, bool isDelay = false)
15         {
16             using (var looper = new ConditionLooper() { Interval = interval, TimeOut = timeOut, IsFirstDelay = isDelay })
17             {
18                 return looper.Run(condition);
19             }
20         }
21 
22         /// <summary>
23         /// 周期性检测<paramref name="condition"/>条件表达式是否满足,直到满足条件或循环检测次数已到则退出。
24         /// </summary>
25         /// <param name="condition">条件表达式。</param>
26         /// <param name="interval">检测时间间隔,默认1000毫秒即1秒。</param>
27         /// <param name="loopTimes">循环检测的次数,-1 为不启用,<paramref name="condition"/>表示的条件表达满足时才会退出。</param>
28         /// <param name="isDelay">首次调用是否延迟<paramref name="interval"/>指定的时间间隔,默认为<seealso cref="false"/></param>
29         /// <returns></returns>
30         public static ConditionLooperResult WaitForTimes(Func<bool> condition, int interval = 1000, int loopTimes = -1, bool isDelay = false)
31         {
32             using (var looper = new ConditionLooper() { Interval = interval, LoopTimes = loopTimes, IsFirstDelay = isDelay })
33             {
34                 return looper.Run(condition);
35             }
36         }
37 
38         /// <summary>
39         /// 异步周期性检测<paramref name="condition"/>条件表达式是否满足,直到满足条件或超时时间已到则退出。
40         /// </summary>
41         /// <param name="condition">条件表达式。</param>
42         /// <param name="callback">退出时的回调函数。</param>
43         /// <param name="interval">检测时间间隔,默认100毫秒。</param>
44         /// <param name="timeOut">检测超时时间,-1 为不启用,<paramref name="condition"/>表示的条件表达满足时才会退出。</param>
45         /// <param name="isDelay">首次调用是否延迟<paramref name="interval"/>指定的时间间隔,默认为<seealso cref="false"/></param>
46         /// <returns>检测结果</returns>
47         public static void WaitAsync(Func<bool> condition, Action<ConditionLooperResult> callback, int interval = 100, int timeOut = -1, bool isDelay = false)
48         {
49             var looper = new ConditionLooper() { Interval = interval, TimeOut = timeOut, IsFirstDelay = isDelay };
50 
51             looper.RunAsync(condition, (result) =>
52             {
53                 callback?.Invoke(result);
54                 looper.Dispose();
55             });
56         }
57 
58         /// <summary>
59         /// 异步周期性检测<paramref name="condition"/>条件表达式是否满足,直到满足条件或循环检测次数已到则退出,通过回调函数返回执行结果。
60         /// </summary>
61         /// <param name="condition">条件表达式。</param>
62         /// <param name="callback">退出时的回调函数。</param>
63         /// <param name="interval">检测时间间隔,默认1000毫秒即1秒。</param>
64         /// <param name="loopTimes">循环检测的次数,-1 为不启用,<paramref name="condition"/>表示的条件表达满足时才会退出。</param>
65         /// <param name="isDelay">首次调用是否延迟<paramref name="interval"/>指定的时间间隔,默认为<seealso cref="false"/></param>
66         /// <returns></returns>
67         public static void WaitForTimesAsync(Func<bool> condition, Action<ConditionLooperResult> callback, int interval = 100, int loopTimes = -1, bool isDelay = false)
68         {
69             var looper = new ConditionLooper() { Interval = interval, LoopTimes = loopTimes, IsFirstDelay = isDelay };
70 
71             looper.RunAsync(condition, (result) =>
72             {
73                 callback?.Invoke(result);
74                 looper.Dispose();
75             });
76         }
77     }

4、判断文件是否被占用 函数

 1         /// <summary>
 2         /// 判断文件是否被占用
 3         /// </summary>
 4         /// <param name="path"></param>
 5         /// <returns></returns>
 6         public static bool IsFileUsing(string path)
 7         {
 8             if (!File.Exists(path))
 9             {
10                 // 文件不存在,则等待文件生成
11                 return true;
12             }
13 
14             var used = true;
15             FileStream fs = null;
16 
17             try
18             {
19 
20                 fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None);
21 
22                 Debug.WriteLine($"not used.");
23                 used = false;
24             }
25             catch
26             {
27             }
28             finally
29             {
30                 if (fs != null)
31                 {
32                     fs.Close();
33                 }
34             }
35 
36             return used;
37         }

5、测试代码段

1             Console.WriteLine($"{string.Format("{0,-4}", System.Threading.Thread.CurrentThread.ManagedThreadId)}{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} -> 启动控制台");
2 
3             var filePath = AppDomain.CurrentDomain.BaseDirectory + "abc.txt";
4             ConditionMonitor.Wait(() =>
5             {
6                 Console.WriteLine($"{string.Format("{0,-4}", System.Threading.Thread.CurrentThread.ManagedThreadId)}->{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
7                 return !ConditionMonitor.IsFileUsing(filePath);
8             }, 1000, -1, true);

6、测试效果

 

posted @ 2022-03-12 15:10  lanwah  阅读(32)  评论(0编辑  收藏  举报