zoukankan      html  css  js  c++  java
  • 对资源加读写锁的容器

    之前写了一篇《对不能用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;
    
  • 相关阅读:
    pydensecrf的inference.py代码的学习
    pydensecrf的使用
    Example of DenseCRF with non-RGB data
    scipy.stats.multivariate_normal的使用
    np.mgrid的用法
    Linux后台命令的使用说明
    实现能够在训练过程中手动更改学习率
    pytorch Debug —交互式调试工具Pdb (ipdb是增强版的pdb)-1-在pytorch中使用
    pytorch实现性别检测
    svn冲突意思
  • 原文地址:https://www.cnblogs.com/waynebaby/p/1993860.html
Copyright © 2011-2022 走看看