使用时需要使用ReaderWriterLockSlim
双重检查锁模式吗?
考虑一下这个场景:我有一个dictionary
。事情是可以加进去的。但事情是不能被移除的。当添加一些内容时,如果我想添加一些东西但它还没有添加,那么在时间上它可能是非常昂贵的操作(仅为几百毫秒,但相对于应用程序的其余部分而言仍然很昂贵),还会有什么收获吗:
如下所示:
void populateIfNotPresent( object thing )
{
_lock.EnterReadLock( ) ;
bool there = _dictionary.ContainsKey(thing);
_lock.ExitReadLock( ) ;
// Remember, the specs say nothing can be removed from this dictionary.
if (!there)
{
_lock.EnterUpgradeableReadLock( ) ;
try
{
if( !_dictionary.ContainsKey( thing ) )
{
_lock.EnterWriteLock( ) ;
try
{
populate( thing ) ;
}
finally
{
_lock.ExitWriteLock( ) ;
}
}
}
finally
{
_lock.ExitUpgradeableReadLock( ) ;
}
}
}
文档说,一次只有一个线程可以进入可升级的读锁,但不会阻止任何其他线程进入读锁,因此显示在双重检查锁中存在值。
你认为如何?这是不是过火了?
发布于 2011-08-04 11:59:24
发布于 2011-08-04 12:03:24
因此,在双重检查锁中似乎有值。
价值多少?好吧,如果您希望看到大量缓存丢失,那么执行可升级的锁可能是有意义的;但是,如果您是而不是,希望看到大量缓存错误,那么您正在执行不必要的锁定。一般说来,我会采用最简单的解决方案来完成任务。优化锁通常不是在哪里你会得到最大的冲击,你的钱,寻找更大的东西,首先优化。
建议:
一些东西可能会给你带来更大的冲击,你的钱是一个条形字典(Java的StripedMap是一个相当好的地方开始,它应该是很难理解)。
StripedMap
/StripedDictionary
的基本思想是有一个锁数组:
object[] syncs = new object[n]();
// also create n new objects
您应该用足够多的条纹对映射进行条带化,以便允许您必须在不发生冲突的情况下输入该方法的线程数。我没有任何数据来支持这一点,但是假设您期望最多有8个线程进入映射,那么您可能需要使用8个或更多的锁(条纹)来确保所有8个线程都可以同时输入映射。如果你想要更好的针对“碰撞”的“保险”,那么创建更多的条纹,比如32条或64条。
当您输入populateIfNotPresent
方法时,根据哈希代码锁定其中一个锁:
void populateIfNotPresent( object thing )
{
lock(syncs[thing.GetHashCode()%syncs.Length])
{
if(!dictionary.ContainsKey(thing))
{
populate(thing);
}
}
}
假设您有8个条纹,现在允许多达8个线程安全地进入并执行一个昂贵的操作,否则会阻塞其他7个线程。当然,假设哈希函数足够健壮,可以提供低复制概率的散列。
如果项目不存在,您已经希望populateIfNotPresent
是昂贵的,但是如果您有一个带条的字典,那么您可以让多个线程在字典的不同扇区上工作,而不会相互碰撞。这将给您带来更大的好处,然后在检查对象是否存在时减少几个CPU周期,因为昂贵的操作是在对象确实存在时进行的。
https://stackoverflow.com/questions/6947499
复制