ABNER.Y

c#多线程读写锁

在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;
        }

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

        
internal void UnLock(MutilThreadDisposeState state)
        {
            Func
<bool> 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<bool> isvalidstate)
        {
            IDisposeState rstate
= null;
            Func
<bool> 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<bool> isvalidstate)
        {
            IDisposeState rstate
= null;
            Func
<bool> 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
<bool> f = () =>
                {
                    g_ReadThreadCount.Clear();
                    g_WriteThreadCount.Clear();
                    
return true;
                };
            g_Lock.WaitForTime(TimeSpan.MaxValue, f);
        }

        
/// <summary>
        
/// 指示当前线程是否有写锁
        
/// </summary>
        
/// <returns></returns>
        public bool HasCurrentLockWrite()
        {
            
bool rb = false;
            Func
<bool> f = () =>
                {
                    rb
= HasCurrentThreadWriteLock();
                    
return true;
                };
            g_Lock.WaitForTime(TimeSpan.MaxValue, f);
            
return rb;
        }
        
/// <summary>
        
/// 指示是否存在任何写锁
        
/// </summary>
        
/// <returns></returns>
        public bool HasLockWrite()
        {
            
bool rb = false;
            Func
<bool> f = () =>
            {
                rb
= HasWriteLock();
                
return true;
            };
            g_Lock.WaitForTime(TimeSpan.MaxValue, f);
            
return rb;
        }
        
#endregion

        
#region IDisposable 成员

        
public void Dispose()
        {
            Func
<bool> 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<ThreadCount>();
        }

        
private List<ThreadCount> g_ThreadCounts;

        
/// <summary>
        
/// 获取当前线程的标识
        
/// </summary>
        
/// <returns></returns>
        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;
        }
        
/// <summary>
        
/// 移除当前线程标识
        
/// </summary>
        public void RemoveThreadCount()
        {
            ThreadCount x
= GetThreadCount();
            
if (x != null)
            {
                x.Count
= x.Count - 1;
                
if (x.Count <= 0)
                    g_ThreadCounts.Remove(x);
            }
        }
        
/// <summary>
        
/// 添加当前线程标识
        
/// </summary>
        public void AddThreadCount()
        {
            ThreadCount x
= GetThreadCount();
            
if (x != null)
                x.Count
= x.Count + 1;
            
else
            {
                x
= new ThreadCount() { Count = 1 };
                g_ThreadCounts.Add(x);
            }
        }
        
/// <summary>
        
/// 获取当前所有线程标识的数量
        
/// </summary>
        public int Count
        {
            
get { return g_ThreadCounts.Count; }
        }
        
/// <summary>
        
/// 判断是否存在不是本线程的标识
        
/// </summary>
        
/// <returns></returns>
        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<MutilThreadDisposeState>();
        }

        
private List<MutilThreadDisposeState> 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 私有方法

        
/// <summary>
        
/// 尝试锁定
        
/// </summary>
        
/// <param name="onenter">成功锁定时调用该回调:返回True指示退出获取锁定,否则继续下一次获取锁定</param>
        
/// <returns>尝试结果</returns>
        private PerWaitEnum TryEnter(Func<bool> 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;
        }

        
/// <summary>
        
/// 等待
        
/// </summary>
        
/// <param name="waittimeout">等待超时值</param>
        
/// <param name="dt">上次等待时间</param>
        
/// <returns>返回True指示未超时</returns>
        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);
            }
        }

/// <summary>
       
/// 计算此时同tp的时间差,同时tp返回此时时间
       
/// </summary>
       
/// <param name="tp">上次等待时间,返回此时</param>
       
/// <returns>tp同此时的时间差</returns>
        private TimeSpan GetNowDateTimeSpan(ref DateTime tp)
        {
            DateTime kk
= tp;
            tp
= DateTime.Now;
           
return tp.Subtract(kk);
        }
       
#endregion

       
#region 公有方法

       
/// <summary>
       
/// 等待指定的时间:timeout
       
/// </summary>
       
/// <param name="timeout">等待超时时间:该值=TimeSpan.MaxValue边示无期限的等待</param>
       
/// <param name="onenter">当每次获得等待锁时都调用,返回True表示退出等待,否则再次等待锁,直到超时</param>
       
/// <returns>True表示成功等待到锁并且onenter函数返回True,False:表示等待超时</returns>
        public bool WaitForTime(TimeSpan timeout, Func<bool> 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
    }

/// <summary>
    
/// 指示某种状态接口
    
/// 本接口一般用在其它对象锁定方法中的返回值:如IReadWriteLock接口方法中的返回值
    
/// 使用using将使在using块中锁定本接口的当前状态
    
/// 调用该接口的IDisposable.Dispose()释放状态锁定
    
/// </summary>
    public interface IDisposeState : IDisposable
    {
        
/// <summary>
        
/// 是否有效状态
        
/// </summary>
        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...

}

}


posted on 2011-05-25 03:15  abner.Y  阅读(904)  评论(0)    收藏  举报

导航