[转载]对资源加读写锁的容器

[转载]对资源加读写锁的容器 – 怕怕的韦恩卑鄙 – 博客园.

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

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

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

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

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

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

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

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

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

}
};
}

#region IDisposable Members

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

///
/// 销毁
///
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)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏