asp.net 多线程读写锁代码

作者:袖梨 2022-06-25

c#中使用多线程同步是一个头痛的问题,比较经常用的是lock(object){}这种方法,但是这种方法在读多写少的时候比较浪费资源,当然c#也提供了一种读写锁,我这里只是提供一个原创读写锁的类的源代码,该类的主要目的是允许多个线程同时读,而仅允许一个线程写,而用lock是不论读写都只能一个线程运行的
有兴趣的可以看看讨论讨论,以下是源代码:
   

public sealed class MutilThreadReadWriterLock : IReadWriteLock,IDisposable
    {

        static MutilThreadReadWriterLock()
        {
            EmptyNullDisposedState = DisposedState.Empty;
            IsValidDisposedState = DisposedState.Valid;
        }

        public MutilThreadReadWriterLock()
        {
            g_ReadThreadCount = new ThreadCountCollection();
            g_WriteThreadCount = new ThreadCountCollection();
            g_Lock = new TimeSpanWaitor();
            g_Disposed = false;
        }

        private ThreadCountCollection g_ReadThreadCount;

        private ThreadCountCollection g_WriteThreadCount;

        private TimeSpanWaitor g_Lock;

        private bool g_Disposed;

        private bool HasReadLock()
        {
            return (g_ReadThreadCount.Count > 0);
        }

        private bool HasCurrentThreadReadLock()
        {
            if (HasReadLock())
                return g_ReadThreadCount.GetThreadCount() != null;
            else
                return false;
        }

        private bool HasNotIsCurrentThreadReadLock()
        {
            if (HasReadLock())
                return g_ReadThreadCount.ContainNotCurrentThreadCount();
            else
                return false;
        }

        private bool HasWriteLock()
        {
            return g_WriteThreadCount.Count > 0;
        }

        private bool HasCurrentThreadWriteLock()
        {
            if (HasWriteLock())
                return g_WriteThreadCount.GetThreadCount() != null;
            else
                return false;
        }

        private bool HasNotIsCurrentThreadWriteLock()
        {
            if (HasWriteLock())
                return g_WriteThreadCount.ContainNotCurrentThreadCount();
            else
                return false;
        }

        ///


        /// 尝试获取读锁
        /// 得到锁的条件:不存在非本线程的写锁
        ///

        ///
        private bool TryLockRead()
        {
            bool b = HasNotIsCurrentThreadWriteLock();
            if (!b)
                g_ReadThreadCount.AddThreadCount();
            return !b;
        }
        ///
        /// 尝试获取写锁
        /// 得到锁的条件:不存在非本线程的读锁 并且 不存在非本线程的写锁
        ///

        ///
        private bool TryLockWrite()
        {
            bool b = HasNotIsCurrentThreadReadLock();
            if (!b)
                b = HasNotIsCurrentThreadWriteLock();
            if (!b)
                g_WriteThreadCount.AddThreadCount();
            return !b;
        }

        internal void UnLock(MutilThreadDisposeState state)
        {
            Func ul = () =>
                {
                    if (((IDisposeState)state).IsValid)
                    {
                        if (state.IsWriteLock)
                            g_WriteThreadCount.RemoveThreadCount();
                        else
                            g_ReadThreadCount.RemoveThreadCount();
                    }
                    return true;
                };
            g_Lock.WaitForTime(TimeSpan.MaxValue, ul);
        }

        #region IReadWriteLock 成员

        public IDisposeState LockRead(TimeSpan timeout)
        {
            return LockRead(timeout, null);
        }

        public IDisposeState LockWrite(TimeSpan timeout)
        {
            return LockWrite(timeout, null);
        }

        public IDisposeState LockRead(TimeSpan timeout,Func isvalidstate)
        {
            IDisposeState rstate = null;
            Func f = () =>
            {
                if (g_Disposed)
                {
                    rstate = DisposedState.Empty;
                    return true;
                }
                if (TryLockRead())
                {
                    bool isvalid = isvalidstate != null ? isvalidstate() : true;
                    if (!isvalid)
                        rstate = DisposedState.Empty;
                    else
                        rstate =
                            MutilThreadDisposeStatePools.GetMutilThreadDisposeState(
                            true, false, this);
                    return true;
                }
                else
                {
                    return false;
                }
            };
            if (g_Lock.WaitForTime(timeout, f))
                return rstate;
            else
                return DisposedState.Empty;
        }

        public IDisposeState LockWrite(TimeSpan timeout, Func isvalidstate)
        {
            IDisposeState rstate = null;
            Func f = () =>
            {
                if (g_Disposed)
                {
                    rstate = DisposedState.Empty;
                    return true;
                }
                if (TryLockWrite())
                {
                    bool isvalid = isvalidstate != null ? isvalidstate() : true;
                    if (isvalid)
                        rstate =
                            MutilThreadDisposeStatePools.GetMutilThreadDisposeState(
                            isvalid, true, this);
                    else
                        rstate = DisposedState.Empty;
                    return true;
                }
                else
                {
                    return false;
                }
            };
            if (g_Lock.WaitForTime(timeout, f))
                return rstate;
            else
                return DisposedState.Empty;
        }

        public void FreeAllLock()
        {
            Func f = () =>
                {
                    g_ReadThreadCount.Clear();
                    g_WriteThreadCount.Clear();
                    return true;
                };
            g_Lock.WaitForTime(TimeSpan.MaxValue, f);
        }

        ///


        /// 指示当前线程是否有写锁
        ///

        ///
        public bool HasCurrentLockWrite()
        {
            bool rb = false;
            Func f = () =>
                {
                    rb = HasCurrentThreadWriteLock();
                    return true;
                };
            g_Lock.WaitForTime(TimeSpan.MaxValue, f);
            return rb;
        }
        ///
        /// 指示是否存在任何写锁
        ///

        ///
        public bool HasLockWrite()
        {
            bool rb = false;
            Func f = () =>
            {
                rb = HasWriteLock();
                return true;
            };
            g_Lock.WaitForTime(TimeSpan.MaxValue, f);
            return rb;
        }
        #endregion

        #region IDisposable 成员

        public void Dispose()
        {
            Func f = () =>
                {
                    g_Disposed = true;
                    return true;
                };
            g_Lock.WaitForTime(TimeSpan.MaxValue, f);
        }

        #endregion


        public static readonly IDisposeState EmptyNullDisposedState;

        public static readonly IDisposeState IsValidDisposedState;
    }
    internal class ThreadCount
    {

        public ThreadCount()
        {
            p_ThreadID = Thread.CurrentThread.ManagedThreadId;
        }

        private int p_ThreadID;

        public int ThreadID
        {
            get { return p_ThreadID; }
        }

        private int p_Count;

        public int Count
        {
            get { return p_Count; }
            set { p_Count = value; }
        }
    }

    internal class ThreadCountCollection
    {

        public ThreadCountCollection()
        {
            g_ThreadCounts = new List();
        }

        private List g_ThreadCounts;

        ///


        /// 获取当前线程的标识
        ///

        ///
        public ThreadCount GetThreadCount()
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            for (int i = 0; i < g_ThreadCounts.Count; i++)
                if (g_ThreadCounts[i].ThreadID == id) return g_ThreadCounts[i];
            return null;
        }
        ///
        /// 移除当前线程标识
        ///

        public void RemoveThreadCount()
        {
            ThreadCount x = GetThreadCount();
            if (x != null)
            {
                x.Count = x.Count - 1;
                if (x.Count <= 0)
                    g_ThreadCounts.Remove(x);
            }
        }
        ///
        /// 添加当前线程标识
        ///

        public void AddThreadCount()
        {
            ThreadCount x = GetThreadCount();
            if (x != null)
                x.Count = x.Count + 1;
            else
            {
                x = new ThreadCount() { Count = 1 };
                g_ThreadCounts.Add(x);
            }
        }
        ///
        /// 获取当前所有线程标识的数量
        ///

        public int Count
        {
            get { return g_ThreadCounts.Count; }
        }
        ///
        /// 判断是否存在不是本线程的标识
        ///

        ///
        public bool ContainNotCurrentThreadCount()
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            for (int i = 0; i < g_ThreadCounts.Count; i++)
                if (g_ThreadCounts[i].ThreadID != id) return true;
            return false;
        }

        public void Clear()
        {
            g_ThreadCounts.Clear();
        }
    }

    internal class DisposedState : IDisposeState
    {

        static DisposedState()
        {
            Empty = new DisposedState();
            Valid = new DisposedState(true);
        }

        public DisposedState()
        {
            p_IsValid = false;
        }

        public DisposedState(bool isvalid)
        {
            p_IsValid = isvalid;
        }

        #region IDisposeState 成员

        private bool p_IsValid;

        public bool IsValid
        {
            get { return p_IsValid; }
        }

        #endregion

        #region IDisposable 成员

        public void Dispose()
        {
        }

        #endregion

        internal static readonly DisposedState Empty;

        internal static readonly DisposedState Valid;
    }

    internal class MutilThreadDisposeState : IDisposeState
    {

        private MutilThreadReadWriterLock g_Owner;

        private bool p_IsValid;

        private bool p_IsWriteLock;

        public bool IsWriteLock
        {
            get { return p_IsWriteLock; }
        }

        #region IDisposeState 成员

        bool IDisposeState.IsValid
        {
            get { return p_IsValid; }
        }

        #endregion

        #region IDisposable 成员

        void IDisposable.Dispose()
        {
            if (g_Owner != null)
                g_Owner.UnLock(this);
            MutilThreadDisposeStatePools.MutilThreadDisposeStateToBuffer(this);
        }

        #endregion

        internal void Reset(bool isvalid,bool iswritelock,MutilThreadReadWriterLock owner)
        {
            p_IsValid = isvalid;
            p_IsWriteLock = iswritelock;
            g_Owner = owner;
        }
    }

    internal class MutilThreadDisposeStatePools
    {

        static MutilThreadDisposeStatePools()
        {
            g_Gobal = new MutilThreadDisposeStatePools();
        }

        public MutilThreadDisposeStatePools()
        {
            g_Buffers = new List();
        }

        private List g_Buffers;

        internal MutilThreadDisposeState GetState(
            bool isvalid, bool iswritelock, MutilThreadReadWriterLock owner)
        {
            lock (g_Buffers)
            {
                if (g_Buffers.Count > 0)
                {
                    MutilThreadDisposeState x = g_Buffers[0];
                    x.Reset(isvalid, iswritelock, owner);
                    g_Buffers.RemoveAt(0);
                    return x;
                }
                else
                {
                    MutilThreadDisposeState x = new MutilThreadDisposeState();
                    x.Reset(isvalid, iswritelock, owner);
                    return x;
                }
            }
        }

        internal void ToBuffer(MutilThreadDisposeState b)
        {
            lock (g_Buffers)
            {
                b.Reset(false, false, null);
                g_Buffers.Add(b);
            }
        }

        internal void ClearBuffer()
        {
            lock (g_Buffers)
            {
                g_Buffers.Clear();
            }
        }

        private static MutilThreadDisposeStatePools g_Gobal;

        internal static MutilThreadDisposeState GetMutilThreadDisposeState(
            bool isvalid, bool iswritelock, MutilThreadReadWriterLock owner)
        {
            return g_Gobal.GetState(isvalid, iswritelock, owner);
        }

        internal static void MutilThreadDisposeStateToBuffer(MutilThreadDisposeState state)
        {
            g_Gobal.ToBuffer(state);
        }

        internal static void ClearGobalBuffer()
        {
            g_Gobal.ClearBuffer();
        }
    }
    public sealed class TimeSpanWaitor
    {

        public TimeSpanWaitor(int minwaitmillseconds, int maxwaitmillsecondes)
        {
            g_AsyncObject = new IntLock();
            g_DefaultWaitTime = new TimeSpan(0, 0, 1);
            int min = minwaitmillseconds;
            if (min < 0)
                min = 10;
            int max = maxwaitmillsecondes;
            if (max < 0)
                max = 100;
            if (min > max)
            {
                int x = min;
                min = max;
                max = x;
            }
            if (min == max)
            {
                min = 10;
                max = 100;
            }
            g_MaxWaitMillSeconds = max;
            g_MinWaitMillSeconds = min;
            g_WaitTimeDom = new Random();
        }

        public TimeSpanWaitor()
            : this(DefaultMinWaitTimeMillSeconds, DefaultMaxWaitTimeMillSeconds)
        {
        }

        #region 公有常数

        public const int DefaultMaxWaitTimeMillSeconds = 100;

        public const int DefaultMinWaitTimeMillSeconds = 10;

        #endregion

        #region 私有常量

        private IntLock g_AsyncObject;

        private TimeSpan g_DefaultWaitTime;

        private Random g_WaitTimeDom = null;

        private int g_MaxWaitMillSeconds = 0;

        private int g_MinWaitMillSeconds = 0;

        #endregion

        #region 私有方法

        ///


        /// 尝试锁定
        ///

        /// 成功锁定时调用该回调:返回True指示退出获取锁定,否则继续下一次获取锁定
        /// 尝试结果
        private PerWaitEnum TryEnter(Func onenter)
        {
            bool success = g_AsyncObject.Lock();
            if (success)
            {
                PerWaitEnum r = PerWaitEnum.SuccessAndContinue;
                Exception err = null;
                try
                {
                    if (onenter())
                        r = PerWaitEnum.SuccessAndExists;
                }
                catch (Exception e)
                {
                    err = e;
                }
                finally
                {
                    g_AsyncObject.UnLock();
                }
                if (err != null)
                    throw err;
                return r;
            }
            return PerWaitEnum.Fail;
        }

        ///


        /// 等待
        ///

        /// 等待超时值
        /// 上次等待时间
        /// 返回True指示未超时
        private bool WaitTime(ref TimeSpan waittimeout, ref DateTime dt)
        {
            if (waittimeout == TimeSpan.MaxValue)
            {
                Thread.Sleep(g_WaitTimeDom.Next(g_MinWaitMillSeconds, g_MaxWaitMillSeconds));
                dt = DateTime.Now;
                return true;
            }
            else if (waittimeout == TimeSpan.MinValue)
            {
                dt = DateTime.Now;
                return false;
            }
            else if (waittimeout == TimeSpan.Zero)
            {
                dt = DateTime.Now;
                return false;
            }
            else
            {
                Thread.Sleep(g_WaitTimeDom.Next(g_MinWaitMillSeconds, g_MaxWaitMillSeconds));
                waittimeout -= GetNowDateTimeSpan(ref dt);
                return (waittimeout.Ticks > 0);
            }
        }
///
        /// 计算此时同tp的时间差,同时tp返回此时时间
        ///

        /// 上次等待时间,返回此时
        /// tp同此时的时间差
        private TimeSpan GetNowDateTimeSpan(ref DateTime tp)
        {
            DateTime kk = tp;
            tp = DateTime.Now;
            return tp.Subtract(kk);
        }
        #endregion

        #region 公有方法

        ///


        /// 等待指定的时间:timeout
        ///

        /// 等待超时时间:该值=TimeSpan.MaxValue边示无期限的等待
        /// 当每次获得等待锁时都调用,返回True表示退出等待,否则再次等待锁,直到超时
        /// True表示成功等待到锁并且onenter函数返回True,False:表示等待超时
        public bool WaitForTime(TimeSpan timeout, Func onenter)
        {
            TimeSpan tmout = timeout;
            DateTime n = DateTime.Now;
            PerWaitEnum r = TryEnter(onenter);
            while (r != PerWaitEnum.SuccessAndExists)
            {
                if (!WaitTime(ref tmout, ref n))
                    break;
                r = TryEnter(onenter);
            }
            return r == PerWaitEnum.SuccessAndExists;
        }
        #endregion
    }

    internal sealed class IntLock
    {

        public IntLock()
        {
            g_Radom = 0;
        }

        private int g_Radom;

        public bool Lock()
        {
            return Interlocked.CompareExchange(
                 ref g_Radom, 1, 0) == 0;
        }

        public bool UnLock()
        {
           return Interlocked.CompareExchange(
                 ref g_Radom, 0, 1) == 1;
        }
    }

    internal enum PerWaitEnum
    {
        SuccessAndExists,
        SuccessAndContinue,
        Fail
    }
 ///


    /// 指示某种状态接口
    /// 本接口一般用在其它对象锁定方法中的返回值:如IReadWriteLock接口方法中的返回值
    /// 使用using将使在using块中锁定本接口的当前状态
    /// 调用该接口的IDisposable.Dispose()释放状态锁定
    ///

    public interface IDisposeState : IDisposable
    {
        ///
        /// 是否有效状态
        ///

        bool IsValid { get; }
    }


使用该类如下:

MutilThreadReadWriterLock x=new MutilThreadReadWriterLock();

TimeSpan sp=new TimeSpan(0,0,1,0);

读锁

using(IDisposeState y=x.LockRead(sp))

{

    if(y.IsValid)

{

    do something...

}

}

写锁

using(IDisposeState y=x.LockWrite(sp))

{

if(y.IsValid)

{

   do something...

}

}

 

相关文章

精彩推荐