锁定与并发

系统 1428 0

在多线程程序中,我们经常需要对要访问的资源进行加锁。加锁的目的是为了同步对资源的访问,但是,加锁不可避免的会降低应用的并发量。那么如何在需要加锁的时候,尽可能地提高并发量了?下面是我的一些经验,仅供参考。

1.首先,我们要控制好锁的粒度。

锁的粒度越大,能支持的并发就越小。

我们只需要将真正需要同步的代码块 lock 住,而不需要同步的代码块不要放在lock块中。

当然,锁的粒度也不是越小越好,粒度太细的锁会导致编程很繁琐,而且需要足够的细心和全面考虑方可保证锁不会出现问题。

在这点上,有一个特别需要注意的是 -- 事件。 事件最好不要在lock块中触发,因为你无法确定组件应用者的事件处理函数会执行多久。 除非,你对一切了然于胸。

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> lock ( this .locker)
{
//

this .OnSomeEvent(); // 触发事件
}

2.杜绝死锁的发生。当发生死锁时,并发将降到最低。

3.区分读写。

我们经常使用 lock 关键字来锁定资源,然而,lock没有办法区分读写。比如,如果当前同时有三个线程在访问资源,且三个都是 读取 资源,如果使用lock,那么,在读取资源上,它们也会被同步处理。幸运的是,.NET为我们提供了读写锁 -- ReaderWriterLock ,使用它,上面的例子便是三个线程可以同时读取资源。

对于那种读取多于修改的资源,区分读写可以极大地提升并发量。

ReaderWriterLock的使用不如lock来得方便,为此,我封装了 SmartRWLocker ,它提供了和ReaderWriterLock一样的功能,但是我们可以像使用lock一样来使用它,如:

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> using ( this .smartRWLocker.Lock( AccessMode .Read))
{
// dosomething
}

SmartRWLocker的实现也相当简单,如下所示:

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> /// <summary>
/// SmartRWLocker简化了ReaderWriterLock的使用。 zhuweisky2008.11.25
/// </summary>
public class SmartRWLocker
{
private ReaderWriterLock readerWriterLock = new ReaderWriterLock ();

public LockingObjectLock( AccessMode accessMode)
{
return new LockingObject ( this .readerWriterLock,accessMode);
}
}

/// <summary>
/// AccessMode访问锁定资源的方式。
/// </summary>
public enum AccessMode
{
Read
= 0 ,
Write
}

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> public class LockingObject :IDisposable
{
private ReaderWriterLock readerWriterLock;
private AccessMode accessMode = AccessMode .Read;

#region Ctor
public LockingObject( ReaderWriterLock _lock, AccessMode _lockMode)
{
this .readerWriterLock = _lock;
this .accessMode = _lockMode;

if ( this .accessMode == AccessMode .Read)
{
this .readerWriterLock.AcquireReaderLock( - 1 );
}
else
{
this .readerWriterLock.AcquireWriterLock( - 1 );
}
}
#endregion

#region IDisposable成员

public void Dispose()
{
if ( this .accessMode == AccessMode .Read)
{
this .readerWriterLock.ReleaseReaderLock();
}
else
{
this .readerWriterLock.ReleaseWriterLock();
}
}
#endregion
}

2009.02.23 附加:

我们都知道,对于集合类,如Lits<>,Dictionary<,>等,

(1)如果其它线程在对其中的元素进行修改(如添加或删除元素)时,正在对集合进行 枚举 的线程会抛出异常。

(2)如果有一个线程正在对集合进行修改,另外一个线程调用Contains/ContainsKey,会抛出异常吗?答案是 不会

锁定与并发


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论