ReaderWriterLock(转)
ReaderWriterLock类
通常来讲,一个类型的实例对于并行的读操作是线程安全的,但是并行地根性操作则不是(并行地读和更新也不是)。 这对于资源也是一样的,比如一个文件。当保护类型的实例安全时,使用一个简单的排它锁即解决问题,但是当有很多的读操作 而偶然的更新操作这就很不合理的限制了并发。一个例子就是这在一个业务程序服务器中,为了快速查找把数据缓存到静态字段中。 在这个方案中,ReaderWriterLock类被设计成提供最大容量的锁定。
ReaderWriterLock为读和写的锁提供了不同的方法——AcquireReaderLock和AcquireWriterLock。两个方法都需要一个超时参数,并且在超时发生后抛出ApplicationException异常(不同于大多数线程类的返回false等效的方法)。超时发生相当容易在资源争用严重的时候。
调用 ReleaseReaderLock或ReleaseWriterLock释放锁。 这些方法支持嵌套锁,ReleaseLock方法也支持一次清除所有嵌套级别的锁。(你可以随后调用RestoreLock类重新锁定相同的级别,它在ReleaseLock之前执行——如此来模仿Monitor.Wait的锁定切换行为)。
你可以调用AcquireReaderLock开始一个read-lock ,然后通过UpgradeToWriterLock把它升级为write-lock。这个方法返回一个可能被用于调用DowngradeFromWriterLock的信息。这个方式允许读程序临时地请求写访问同时不必必须在降级之后重新排队列。
在接下来的这个例子中,4个线程被启动:一个不停地往列表中增加项目;另一个不停地从列表中移除项目;其它两个不停地报告列表中项目的个数。前两者获得写的锁,后两者获得读的锁。每个锁的超时参数为10秒。(异常处理一般要使用来捕捉ApplicationException,这个例子中出于方便而省略了)
class Program {
static ReaderWriterLock rw = new ReaderWriterLock ();
static List <int> items = new List <int> ();
static Random rand = new Random ();
static void Main (string[] args) {
new Thread (delegate() { while (true) AppendItem(); } ).Start();
new Thread (delegate() { while (true) RemoveItem(); } ).Start();
new Thread (delegate() { while (true) WriteTotal(); } ).Start();
new Thread (delegate() { while (true) WriteTotal(); } ).Start();
}
static int GetRandNum (int max) { lock (rand) return rand.Next (max); }
static void WriteTotal() {
rw.AcquireReaderLock (10000);
int tot = 0; foreach (int i in items) tot += i;
Console.WriteLine (tot);
rw.ReleaseReaderLock();
}
static void AppendItem () {
rw.AcquireWriterLock (10000);
items.Add (GetRandNum (1000));
Thread.SpinWait (400);
rw.ReleaseWriterLock();
}
static void RemoveItem () {
rw.AcquireWriterLock (10000);
if (items.Count > 0)
items.RemoveAt (GetRandNum (items.Count));
rw.ReleaseWriterLock();
}
}
往List中加项目要比移除快一些,这个例子在AppendItem中包含了SpinWait来保持项目总数平衡。
按照请求到达的顺序,一共有四种
Reader-Reader,第二个不需等待,直接获得读控制权;
Reader-Writer,第二个需要等待第一个调用ReleaseReaderLock()释放读控制权后,才能获得写控制权;
Writer-Writer,第二个需要等待第一个调用ReleaseWriterLock()释放写控制权后,才能获得写控制权;
Writer-Reader,第二个需要等待第一个调用ReleaseWriterLock()释放写控制权后,才能获得读控制权。
作者:CoderZh
公众号:hacker-thinking (一个程序员的思考)
独立博客:http://blog.coderzh.com
博客园博客将不再更新,请关注我的「微信公众号」或「独立博客」。
作为一个程序员,思考程序的每一行代码,思考生活的每一个细节,思考人生的每一种可能。
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。