VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > c#编程 >
  • 指令等待模型

代码有所修改,但暂时没时间,提一下是关于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模型也可以用作一个闹钟。上述模型避免了外部类注册回调或事件,提供了类间的松散耦合


相关教程