惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
aimingoo的专栏
aimingoo的专栏
Y
Y Combinator Blog
Vercel News
Vercel News
Blog — PlanetScale
Blog — PlanetScale
有赞技术团队
有赞技术团队
P
Proofpoint News Feed
WordPress大学
WordPress大学
V
V2EX
The Register - Security
The Register - Security
博客园 - 聂微东
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - Franky
D
DataBreaches.Net
G
Google Developers Blog
O
OpenAI News
S
Schneier on Security
Simon Willison's Weblog
Simon Willison's Weblog
I
Intezer
Engineering at Meta
Engineering at Meta
Recorded Future
Recorded Future
T
Threatpost
The Hacker News
The Hacker News
Cisco Talos Blog
Cisco Talos Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
B
Blog RSS Feed
Apple Machine Learning Research
Apple Machine Learning Research
T
The Exploit Database - CXSecurity.com
L
LINUX DO - 热门话题
G
GRAHAM CLULEY
博客园 - 叶小钗
V
Vulnerabilities – Threatpost
云风的 BLOG
云风的 BLOG
L
LINUX DO - 最新话题
MyScale Blog
MyScale Blog
L
LangChain Blog
Scott Helme
Scott Helme
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
雷峰网
雷峰网
Google Online Security Blog
Google Online Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
N
News | PayPal Newsroom
NISL@THU
NISL@THU
M
MIT News - Artificial intelligence
Cloudbric
Cloudbric
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Cloudflare Blog
Recent Announcements
Recent Announcements

博客园 - MSFT:waywa 韦恩卑鄙

[UWP]一种利用Behavior 将StateTrigger集中管理的方案 【干货】个人工作文档节选:XAML MVVM 框架易用性细节优化Tips MVVM Sidekick Win8 RT 轻量级MVVM框架开源 对不能用using的成对操作,快速扩展IDisposable的方法 intel I7平台Win7 x64 下wpf、silverlight 与aero特效动画缓慢故障排除一则 今天被Prism里面的一段代码雷到了 1080*1920 下看网站很爽 游戏大厅 从基础开始(8)--绕回来细说聊天室(下)垃圾列表 游戏大厅 从基础开始(7)--绕回来细说聊天室(中间偏下)之女仆编年史2 游戏大厅 从基础开始(6)--绕回来细说聊天室(中)之女仆编年史1 - MSFT:waywa 韦恩卑鄙 游戏大厅 从基础开始(5)--绕回来细说聊天室(上) 简单的树遍历枚举器v0.2-挑战一个程序员到底能多懒- 添加广度优先遍历 一时技痒 不用模拟第一印象的构造 通过三个观察得来的规律解决N^2个往返接力问题 游戏大厅 从基础开始(4)-通过L2X用配置文件反射组装程序(VB only) 关于silverlight depencyobject简单的clone silver light 2 客户端的伪DataTable for EF X360吉他英雄4鼓套装 &1 TB硬盘入手 游戏大厅 从基础开始(3.5)——最吸引眼球的部分 客户端与服务器的连接 的实现 游戏大厅 从基础开始(3)——最吸引眼球的部分 客户端与服务器的连接
对资源加读写锁的容器
MSFT:waywa 韦恩卑鄙 · 2011-03-24 · via 博客园 - MSFT:waywa 韦恩卑鄙

之前写了一篇《对不能用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;