-
指令等待模型
代码有所修改,但暂时没时间,提一下是关于OnWaitComplete和OnWaitTimeout以及IsWaiting属性,为了在Onxx方法中可以继续下一个等待,而先将IsWaiting置false,再调用Onxx方法
a. 单等待模型
用于需要等待某事件的响应或定时等待。在等待时间比较长的时候可考虑使用。
using System; using System.Threading; namespace Hu { public abstract class TimeoutHandler : IDisposable { AutoResetEvent _auto = new AutoResetEvent(false); public bool IsWaiting { get { return _isWaiting; } } protected volatile bool _isWaiting = false; public int Timeout { get { return _timeout; } set { if (value < 0 && value != -1) throw new ArgumentException("值必须为小于int.MaxValue的非负数或为-1"); } } protected int _timeout; protected TimeoutHandler() : this(10000) { } protected TimeoutHandler(int timeoutMs) { _timeout = timeoutMs; } ~TimeoutHandler() { if (_auto != null) _auto.Dispose(); } /// <summary> /// 异步进行<see cref="Timeout"/>指定毫秒数的等待。 /// 返回true表示操作成功,false表示前一次等待未结束。 /// </summary> /// <param name="info"></param> /// <returns></returns> public bool DoWait(object info = null) { if (true == IsWaiting) return false; _isWaiting = true; Action<object> waitDel = Wait; waitDel.BeginInvoke(info, new AsyncCallback(ar => { try { Action<object> del = ar.AsyncState as Action<object>; del?.EndInvoke(ar); } catch { } _isWaiting = false; }), waitDel); return true; } /// <summary> /// 结束当前等待。 /// 返回true表示操作成功,反之操作失败或当前不在异步等待状态(通过<see cref="IsWaiting"/>获取)。 /// </summary> /// <returns></returns> public bool CeaseWait() { if (true == IsWaiting) // 防止没有异步等待时的误操作影响后续判断 return _auto.Set(); return false; } public void Dispose() { _auto.Dispose(); } /// <summary> /// 等待超时 /// </summary> /// <param name="info"></param> protected abstract void OnWaitTimeout(object info); /// <summary> /// 在<see cref="Timeout"/>前,结束了等待 /// </summary> /// <param name="info"></param> protected virtual void OnWaitCompleted(object info) { } private void Wait(object info) { bool succeed = _auto.WaitOne(Timeout); if (true == succeed) OnWaitCompleted(info); else OnWaitTimeout(info); } } }
b. 多等待模型
用于需要在短时间等待若干事件的响应进行后续操作的情况。
using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace Hu { public class TaskInfo : IEquatable<TaskInfo> { public string TaskID { get; internal set; } public int Timeout { get; internal set; } public bool IsTimeout { get; internal set; } public bool IsCanceled { get; internal set; } public TaskInfo(string vTaskID, int vTimeoutMs) { if (string.IsNullOrEmpty(vTaskID)) throw new ArgumentNullException("vTaskID"); TaskID = vTaskID; if (vTimeoutMs < 0 && vTimeoutMs != -1) throw new ArgumentException("vTimeoutMs必须为小于int.MaxValue的非负数"); Timeout = vTimeoutMs; } public bool Equals(TaskInfo other) { if (null == other) return false; return TaskID.CompareTo(other.TaskID) == 0; } public override bool Equals(object obj) { TaskInfo ti = obj as TaskInfo; if (null == ti) return false; return TaskID.CompareTo(ti.TaskID) == 0; } public override int GetHashCode() { return base.GetHashCode(); } } public abstract class MultiTimeoutHandler { readonly object _syncLock = new object(); protected List<TaskInfo> _lstTaskInfo = new List<TaskInfo>(); public bool DoWait(TaskInfo info) { if (false == Monitor.TryEnter(_syncLock, 2000)) return false; try { var ti = _lstTaskInfo.FirstOrDefault(t => t.TaskID.CompareTo(info.TaskID) == 0); if (ti != null) return false; _lstTaskInfo.Add(info); Action<TaskInfo> ta = WaitTask; ta.BeginInvoke(info, new AsyncCallback(ar => { try { Action<TaskInfo> del = ar.AsyncState as Action<TaskInfo>; del.EndInvoke(ar); } catch { } }), ta); } finally { Monitor.Exit(_syncLock); } return true; } public bool CeaseWait(string taskID) { if (false == Monitor.TryEnter(_syncLock, 2000)) return false; try { var ti = _lstTaskInfo.FirstOrDefault(t => t.TaskID.CompareTo(taskID) == 0); if (ti == null) throw new ArgumentException("没有与指定任务标识匹配的任务信息", "taskID"); ti.IsCanceled = true; return true; } finally { Monitor.Exit(_syncLock); } } protected abstract void OnWaitTimeout(TaskInfo info); protected virtual void OnWaitCompleted(TaskInfo info) { } private void WaitTask(TaskInfo info) { DateTime st = DateTime.Now; SpinWait sw = new SpinWait(); while (false == info.IsCanceled) { sw.SpinOnce(); info.IsTimeout = (DateTime.Now - st >= TimeSpan.FromMilliseconds(info.Timeout)); if (true == info.IsTimeout) break; } if (true == info.IsTimeout) WaitTimeout(info); else WaitCompleted(info); } private void WaitTimeout(TaskInfo info) { lock (_syncLock) { bool removed = _lstTaskInfo.Remove(info); } OnWaitTimeout(info); } private void WaitCompleted(TaskInfo info) { lock (_syncLock) { bool removed = _lstTaskInfo.Remove(info); } OnWaitCompleted(info); } } public class TestC : MultiTimeoutHandler { protected override void OnWaitTimeout(TaskInfo info) { Console.WriteLine("Timeout: {0}|{1}|{2}|{3}", info.TaskID, info.Timeout, info.IsCanceled, info.IsTimeout); } } }
有些时候,比如客户端使用udp向服务端发送命令后,可能需要客户端在一段时间内没接收到服务端应答时进行重发等操作,可以考虑a模型;a模型也可以用作一个闹钟。上述模型避免了外部类注册回调或事件,提供了类间的松散耦合
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比
一款纯 JS 实现的轻量化图片编辑器
关于开发 VS Code 插件遇到的 workbench.scm.
前端设计模式——观察者模式
前端设计模式——中介者模式
创建型-原型模式