对资源加读写锁的容器

之前写了一篇《对不能用using的成对操作,快速扩展IDisposable的方法》提到了如何快速的把销毁操作用闭包的形式封装为IDisposable,并且实现了一个ReaderWriteerLockSlimHelper。

 

对于没有using的RWLock似乎已经很好用了, 但是我仍嫌弃其不够简单。

 

资源读写锁的应用,绝大多数是针对某批特定的资源。如果为这样的资源做一个封装,资源的引用需要被隐藏在封装内,封装外不通过读锁不可以访问资源。显然ReaderWriteerLockSlimHelper却无法做到这一点。

 

我们在上文中已经建立了一个 Disposable对象,取得该对象意味着我们可以加锁,将其销毁我们就可以解锁,其生存期与整个加锁周期吻合。对于读写锁来说具有这种行为的对象是一种作为读写钥匙/令牌的存在。解锁后的资源引用放在这个令牌上作为属性暴露出来再合适不过了。

以此为考量,我们先设计一个实现IDisposable,读写锁的令牌

 
  
/// <summary>
/// 读写资源的令牌
/// </summary>
public abstract class LockToken < T > : IDisposable
{
protected LockableObjectContainer < T > _container;

/// <summary>
/// 被锁住的资源引用
/// </summary>
public T Value { get ; set ; }
/// <summary>
/// 读写锁的原钥匙,对其销毁即为解锁
/// </summary>
protected IDisposable _innerTicket;


/// <summary>
/// 创建读写资源的令牌
/// </summary>
/// <param name="value"> 解锁的资源引用 </param>
/// <param name="innerTicket"> 锁的真实引用 </param>
/// <param name="beforeDispose"> 在解锁前需要做的操作 如把资源的新值覆盖回锁住的资源 </param>
/// <param name="afterDispose"> 在解锁后需要做的操作 如写日志 </param>
internal LockToken(LockableObjectContainer < T > container, IDisposable innerTicket, Action < LockToken < T >> beforeDispose, Action < LockToken < T >> afterDispose)
{
_container=container;
_innerTicket
= innerTicket;
Value
= container._value;
this ._disposeAction =
()
=>
{
try
{

if (beforeDispose != null ) beforeDispose( this );
this .Value = default (T);
_innerTicket.Dispose();
if (afterDispose != null ) afterDispose( this );
}
catch
{


}
};
}

#region IDisposable Members

/// <summary>
/// 令牌销毁时要做的操作
/// </summary>
Action _disposeAction;

/// <summary>
/// 销毁
/// </summary>
public void Dispose()
{
_disposeAction();
}

#endregion
}

读写时,所做的操作略有不同。写令牌在销毁时要把令牌上的新引用/值 覆盖到容器内

依此我们可以做两个不同的令牌子类

 

 
  
class ReadLockToken < T > : LockToken < T >
{
public ReadLockToken(LockableObjectContainer < T > container, ReaderWriterLockSlim _lock) :
base (container, _lock.CreateLockScope(LockType.Read), null , null )
{
}

}



class WriteLockToken < T > : LockToken < T >
{
public WriteLockToken(LockableObjectContainer < T > container, ReaderWriterLockSlim _lock)
:
base
(
container,
_lock.CreateLockScope(LockType.Write),
lt
=>
{
// 在解锁前 把新值保存给原对象
lt ._container._value = lt.Value;
           },
          null
)
{
}

}

这些做好后,编写容器就很容易了

 

 

 

 
  
public class LockableObjectContainer<T>
{
internal protected T _value;


System.Threading.ReaderWriterLockSlim _lock
= new
System.Threading.ReaderWriterLockSlim();
public
LockableObjectContainer(T value)
{
_value
=
value;

}

public LockToken<T>
GetReadToken()
{
return new ReadLockToken<T>(this
, _lock);
}
public LockToken<T>
GetWriteToken()
{
return new WriteLockToken<T>(this
, _lock);

}

}

 

 

上面的内容很枯燥

写读写锁的时候很方便

 

 
  
static LockableObjectContainer < Dictionary < Type ,IFactoryContainer > > planConnectionGetters
= new LockableObjectContainer < Dictionary < Type, IFactoryContainer >>
(
new Dictionary < Type, IFactoryContainer > ());


。。。。。。。。。。。。。。。。。。。。。。。。。



using (var token = planConnectionGetters.GetReadToken())
{
var dic
= token.Value;

if (dic.TryGetValue(contractType , out channelFactory ))
{
return channelFactory.GetChannel (uri);

}

}


using (var token = planConnectionGetters.GetWriteToken ())
{
var dic
= token.Value;

if ( ! dic.TryGetValue(contractType, out channelFactory))
{
Type t
= typeof (FactoryContainer <> );
channelFactory
= Activator.CreateInstance(t.MakeGenericType(contractType)) as IFactoryContainer;
dic.Add(contractType, channelFactory);

}



}
 如果容器经常保存字典等常用集合对象 我们也可以这样做一些扩展方法
 
  
public static TValue GetOrCreateValue < TKey, TValue >
(
this LockableObjectContainer < IDictionary < TKey, TValue >> container,
TKey key,
Predicate
< TValue > valueChecker,
Func
< TValue > valueFactory
)
{
TValue val
= default (TValue);
using (var token = container.GetReadToken())
{

var dic
= token.Value;
if (dic.TryGetValue(key, out val))
{
if (valueChecker (val))
return val;

}
}

using (var token = container.GetWriteToken())
{
var dic
= token.Value;
if (dic.TryGetValue(key, out val))
{
if (valueChecker(val))
return val;

}
val
= valueFactory();
dic.Add(key,val) ;

}
return val;

}




------------------------------------------------------------

TQueue q;
q
= instanceQueues.GetOrCreateValue(instance, _ => true , () => new TQueue());
return q;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值