线程基础4

Reader-Writer Locks读写锁:
*

互斥锁是一种简单的保护共享数据的方式,但其并非总是最高效的,应用程序可能经常存在这样的代码:一些代码更新共享数据,而另一些代码仅仅读取这些共享数据。另一些应用程序可能存在大量的读数据行为,数据仅周期性的更新。

因为读数据不改变任何东西,所以只要你确定在你试图读数据时没有其他的线程在更新数据则多个线程同时读取数据不会出现任何错误,典型地仅希望每次一个线程来更新数据。
*
**
ReaderWriterLock 和ReaderWriterLockSlim对象适用于这样的场景:允许多个并发的读者来读数据,但是一旦数据需要被改变,则有一个线程必须临时的互斥地访问那个块共享内存。

使用ReaderWriterLock 可请求一个读锁或写锁,(锁是操作系统资源,属于非托管资源,谨慎使用之),如果获取一个读锁,则可以安全地读取数据,其他的线程也可以获取读锁并安全的读取数据。
在想更新数据之前,必须获取一个写锁,当请求写锁时,任何其他的正在请求读锁或写锁的线程都会被阻塞。如果任何其他的读锁或写锁正在处理中(当你请求写锁时,正有其他的线程在读或写数据),你的线程会被阻塞直到它们被全部释放。当没有任何读或写锁关联到共享数据上时,你才可以获取写锁,在你获取写锁后直至你释放写锁为止,其他任何锁(读或写)都不会被其他的线程获取,所以写锁是一个互斥锁。

在释放写锁后,任何待处理的请求锁的操作会继续————允许仅一个写者或多个可同时访问数据的读者。使用读写锁的方式同互斥锁的方式一样:
**
***
首先创建一个读写锁的实例:
Private mRWLock As New System.Threading.ReaderWriterLock
你可以在一个应用程序中根据需要创建多个读写锁对象,
第二部使用锁:
mRWLock.AcquireWriterLock(100)
Try
‘访问数据
Finally
'释放锁 在.net框架中凡是实现了Dispose模式的类
'可以使用Using语法,来生成Try finally块(编译器做这些事)。
mRWLock.ReleaseWriterLock()

End Try

注意使用锁时应该使用Try finally块,确保无论是否发生异常锁都会被释放。 没有释放锁的后果很严重,可能导致应用程序部稳定甚至崩溃!!!没有释放锁可能会阻塞其它线程,甚至是永远阻塞这时就导致了死锁情形,或者获取锁的线程有超时机制,特定时间范围内没有获取锁则抛出异常导致应用程序失败。写锁的使用同上:
mRWLock.AcquireReaderLock(100)
Try
‘访问数据
Finally
mRWLock.ReleaseReaderLock()
End Try
***
****
.net3.5有一个新锁类型:ReaderWriterLockSlim,
该类实例可提升读能力,前面的锁存在一些问题如:不能自动提升读能力,并且性能不佳,而新的ReaderWriterLockSlim对象给予写更高的优先权,它假设写锁的获取很少发生,所以优先机制更能提升性能。微软不能在前面的.net框架中修复ReaderwriterLock所以引入了这个新锁,它支持的主要方法如下:
dispose: 释放该对象持有的所以资源。
EnterReadLock: 试着获取一个读锁;
EnterUpgradeablereadLock: 试着以升级模式获取一个读锁;
EnterWriteLock:   试着获取一个写锁;
ExitreadLock: 退出读锁;
ExitUpgradeableReadLock: 退出升级模式的读锁。
ExitWriteLock: 退出写锁;
TryEnterReadLock:读模式下试着获取锁,可选可设置一个超时。
TryEnterUpgradeableReadLock:在升级读模式下试着获取锁,可选设置一个超时。
TryEnterWriteLock:在写模式下试着进入锁,可选设置一个超时。

新的读写锁支持三中模式:读,升级读,和写模式,新加入的升级读模式允许我们安全地在读和写模式下转换。此锁支持一种自动的升级通道并且不会像老锁ReaderwriterLock那样导致死锁。但是仅允许一个线程进入升级读模式。

****
*****
AutoReset Events
Monitor(syncLock)和ReaderWriterLock锁都遵从acquire/release模式,它们都可能会阻塞直到其获取到一个锁。
AutoResetEvent 和 ManualResetEvent对象使得,线程自愿选择是否等待一个事件对象,当等待时它们阻塞不做任何事情,当其他的线程激发那个事件时,等待在事件上的所有线程被释放并继续工作。

(通知与发信号同语义)
事件对象可处在:通知的和未通知的两种状态之一。当事件被通知了等待在事件对象上的线程被释放。如果线程在一个通知的事件上调用WaitOne,则线程不会阻塞,如果线程在一个未通知的事件上调用WaitOne则线程会阻塞,直到其他的线程调用对象的Set方法来通知事件对象阻塞的线程才被解阻塞。


AutoResetEvent对象在任何线程调用WaitOne方法时自动重置其自身到未通知状态。另一方面如果一个AutoResetEvent对象未被通知则调用WaitOne的线程会被阻塞,其他的线程来调用Set方法来通知事件对象,这会解阻塞等待中的线程并立即重置AutoResetEvent对象到未通知状态。
我们可使用AutoResetEvent对象来协调使用共享数据的线程们:
Dim mWait As New System.Threading.AutoResetEvent(False)
False参数使得对象处于未通知状态。而TRUE使其处于通知(signaled)状态,此时第一个调用WaitOne方法的线程不会阻塞,但会触发事件对象自动重置到未通知状态。
mWait.WaitOne()//等待或继续运行
mWait.Set()//解阻塞其他等待的线程


ManualResetEvents的使用同AutoResetEvent类似。不同在于:ManualResetEvent使得我们完全控制事件对象的状态到通知或未通知状态,事件对象的状态从来不会自动切换。
这意味着我们必须手动调用Reset方法,而不是依赖它自动发生。这使得我们对过程有更多的控制权并可能潜在或取一些性能提升。
Dim mWait As New System.Threading.ManualResetEvent(True)//生成一个等待对象
mWait.WaitOne()
mWait.Reset()
mWait.set()

*****

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值