原创:c#多线程读写锁
时间:2011-05-23 来源:悠竹客
在c#中使用多线程同步是一个头痛的问题,比较经常用的是lock(object){}这种方法,但是这种方法在读多写少的时候比较浪费资源,当然c#也提供了一种读写锁,我这里只是提供一个原创读写锁的类的源代码,有兴趣的可以看看讨论讨论,以下是源代码:
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...
}
}
相关阅读 更多 +