分享

c#多线程读写锁

 昵称597197 2011-06-02

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

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

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

///
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;

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

///
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<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 私有方法

///
/// 尝试锁定
///

/// 成功锁定时调用该回调:返回True指示退出获取锁定,否则继续下一次获取锁定
/// 尝试结果
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;
}

///
/// 等待
///

/// 等待超时值
/// 上次等待时间
/// 返回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<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
}

///
/// 指示某种状态接口
/// 本接口一般用在其它对象锁定方法中的返回值:如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...

}

}


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多