指令等待模型

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();
        }

        /// 
        /// 异步进行指定毫秒数的等待。
        /// 返回true表示操作成功,false表示前一次等待未结束。
        /// 
        /// 
        /// 
        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;
        }

        /// 
        /// 结束当前等待。
        /// 返回true表示操作成功,反之操作失败或当前不在异步等待状态(通过获取)。
        /// 
        /// 
        public bool CeaseWait()
        {
            if (true == IsWaiting)  // 防止没有异步等待时的误操作影响后续判断
                return _auto.Set();

            return false;
        }

        public void Dispose()
        {
            _auto.Dispose();
        }

        /// 
        /// 等待超时
        /// 
        /// 
        protected abstract void OnWaitTimeout(object info);

        /// 
        ///前,结束了等待
        /// 
        /// 
        protected virtual void OnWaitCompleted(object info)
        { }

        private void Wait(object info)
        {
            bool succeed = _auto.WaitOne(Timeout);
            if (true == succeed)
                OnWaitCompleted(info);
            else
                OnWaitTimeout(info);
        }

    }
}
View Code

b. 多等待模型

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace Hu
{
    public class TaskInfo : IEquatable
    {
        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 _lstTaskInfo = new List();

        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 ta = WaitTask;
                ta.BeginInvoke(info, new AsyncCallback(ar =>
                {
                    try
                    {
                        Action del = ar.AsyncState as Action;
                        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);
        }
    }
}
View Code

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

 

你可能感兴趣的:(指令等待模型)