[.net 多线程 ]ReaderWriterLock
ReaderWriterLock 用于同步对资源的访问。在任一特定时刻,它允许多个线程同时进行读访问,或者允许单个线程进行写访问。在资源不经常发生更改的情况下,ReaderWriterLock 所提供的吞吐量比简单的一次只允许一个线程的锁(如 Monitor)更高。
在多数访问为读访问,而写访问频率较低、持续时间也比较短的情况下,ReaderWriterLock 的性能最好。多个读线程与单个写线程交替进行操作,所以读线程和写线程都不会长时间阻止。
注意
长时间持有读线程锁或写线程锁会使其他线程发生饥饿 (starve)。为了得到最好的性能,需要考虑重新构造应用程序以将写访问的持续时间减少到最小。
一个线程可以持有读线程锁或写线程锁,但是不能同时持有两者。若要获取写线程锁,请使用 UpgradeToWriterLock 和 DowngradeFromWriterLock,而不要通过释放读线程锁的方式获取。
递归锁请求会增加锁上的锁计数。
读线程和写线程将分别排入各自的队列。当线程释放写线程锁时,此刻读线程队列中的所有等待线程都将被授予读线程锁;当已释放所有读线程锁时,写线程队列中处于等待状态的下一个线程(如果存在)将被授予写线程锁,依此类推。换句话说,ReaderWriterLock 在一组读线程和一个写线程之间交替进行操作。
当写线程队列中有一个线程在等待活动读线程锁被释放时,请求新的读线程锁的线程会排入读线程队列。即使它们能和现有的阅读器锁持有者共享并发访问,也不会给它们的请求授予权限;这有助于防止编写器被阅读器无限期阻止。
大多数在 ReaderWriterLock 上获取锁的方法都采用超时值。使用超时可以避免应用程序中出现死锁。例如,某个线程可能获取了一个资源上的写线程锁,然后请求第二个资源上的读线程锁;同时,另一个线程获取了第二个资源上的写线程锁,并请求第一个资源上的读线程锁。如果不使用超时,这两个线程将出现死锁。
如果超时间隔过期并且没有授予锁请求,则此方法通过引发 ApplicationException 将控制返回给调用线程。线程可以捕捉此异常并确定下一步要进行的操作。
static void Main(string[] args)
{
Dictionary<int, string> dic = new Dictionary<int, string>();
ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
Task.Factory.StartNew(() =>
{
int key = ;
while (key <= )
{
Thread.Sleep();
string info = $"写线程:{DateTime.Now.ToString("hhMMss-fff")}";
if (lockSlim.TryEnterWriteLock())
{
try
{
dic.Add(key++, info);
Console.WriteLine(info);
}
catch (Exception ex)
{
;
}
finally
{
Console.WriteLine($"释放 {info}");
lockSlim.ExitWriteLock();
}
}
}
});
Task.Factory.StartNew(() =>
{
while (true)
{
Thread.Sleep();
int key = ;
if (lockSlim.TryEnterReadLock())
{
try
{
while (key < dic.Count)
{
Console.WriteLine($"读线程1:{dic[key++]}");
}
}
catch (Exception ex)
{
;
}
finally
{
lockSlim.ExitReadLock();
}
}
}
});
Task.Factory.StartNew(() =>
{
while (true)
{
Thread.Sleep();
int key = ;
if (lockSlim.TryEnterReadLock())
{
try
{
while (key < dic.Count)
{
Console.WriteLine($"读线程2:{dic[key++]}");
}
}
catch (Exception ex)
{
;
}
finally
{
lockSlim.ExitReadLock();
}
}
}
});
Task.Factory.StartNew(() =>
{
while (true)
{
Thread.Sleep();
int key = ;
if (lockSlim.TryEnterReadLock())
{
try
{
while (key < dic.Count)
{
Console.WriteLine($"读线程3:{dic[key++]}");
}
}
catch (Exception ex)
{
;
}
finally
{
lockSlim.ExitReadLock();
}
}
}
});
Task.Factory.StartNew(() =>
{
while (true)
{
Thread.Sleep();
int key = ;
if (lockSlim.TryEnterReadLock())
{
try
{
while (key < dic.Count)
{
Console.WriteLine($"读线程4:{dic[key++]}");
}
}
catch (Exception ex)
{
;
}
finally
{
lockSlim.ExitReadLock();
}
}
}
});
Console.ReadKey();
}
.NET 同步与异步之锁(ReaderWriterLockSlim)(八)
c#线程同步系列(二) c#中ReaderWriterLock的使用
读写锁ReaderWriterLockSlim
[.net 多线程 ]ReaderWriterLock的更多相关文章
- C#多线程---ReaderWriterLock实现线程同步
一.简介 当我们需要对一个共享资源多次读取的时候,用前面Monitor的同步锁就没有必要了.因为同步锁每次只允许一个线程访问共享资源,其他线程都会阻塞. 此时,通过ReaderWriterLock类可 ...
- 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock
[源码下载] 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLoc ...
- C#多线程:使用ReaderWriterLock类实现多用户读/单用户写同步
摘要:C#提供了System.Threading.ReaderWriterLock类以适应多用户读/单用户写的场景.该类可实现以下功能:如果资源未被写操作锁定,那么任何线程都可对该资源进行读操作锁定, ...
- 多线程中的锁系统(二)-volatile、Interlocked、ReaderWriterLockSlim
上章主要讲排他锁的直接使用方式.但实际当中全部都用锁又太浪费了,或者排他锁粒度太大了,本篇主要介绍下升级锁和原子操作. 阅读目录 volatile Interlocked ReaderWriterLo ...
- ReaderWriterLock的UpgradeToWriterLock方法的一种使用场景
ReaderWriterLock对比互斥锁(lock)的优势是,读锁和写锁的分离,读锁之间互不排斥. 当然,本文重点不是讲ReaderWriterLock本身,而是讲它的UpgradeToWriter ...
- C#多线程技术总结(同步)
二.串行(同步): 1.lock.Monitor--注意锁定的对象必需是引用类型(string类型除外) 示例: private static object syncObject = new obje ...
- C#多线程总结
线程的创建 Thread var thread = new Thread(() => { Console.WriteLine("thread start:" + Thread ...
- C#多线程操作界面控件的解决方案(转)
C#中利用委托实现多线程跨线程操作 - 张小鱼 2010-10-22 08:38 在使用VS2005的时候,如果你从非创建这个控件的线程中访问这个控件或者操作这个控件的话就会抛出这个异常.这是微软为了 ...
- 【五子棋AI循序渐进】——多线程搜索
关于多线程搜索,有很多方法来实现,很多文章推荐基于MTD(F)的方式.好处不言而喻,不过我的程序中采用的是基于PVS的多线程搜索.实现起来主要是这几个方面问题需要解决: 1.置换表的互斥访问. 2.局 ...
随机推荐
- java图形用户界面练习。j2se
总结:主要是如何布局.还是存在很大问题 package clientFrame; import java.awt.FlowLayout; import javax.swing.JButton; imp ...
- MyBatis collection的两种形式——MyBatis学习笔记之九
与association一样,collection元素也有两种形式,现介绍如下: 一.嵌套的resultMap 实际上以前的示例使用的就是这种方法,今天介绍它的另一种写法.还是以教师映射为例,修改映射 ...
- 静态方法staticmethod类方法classmethod
静态方法 只是名义上归类管理,实际上在静态方法里访问不了类或者实例中的任何属性. 类方法 只能访问类变量,不能访问实例变量 属性方法 把一个方法变成一个静态属性,调用的时候不能加() 如果这种属性方法 ...
- js作用域和作用域链
作用域 首先要知道一点,js跟python都是一样的,先编译后执行 唯一的区别在于,js对于只声明,未定义的变量,报错是未定义,后面代码会有这个例子 编译的过程只有赋值和开辟空间的过程 只有函数,类才 ...
- 路边拾遗之其他模块(struct/csv/xlwt/smtp)
struct模块 最近在学习python网络编程这一块,在写简单的socket通信代码时,遇到了struct这个模块的使用,当时不太清楚这到底有和作用,后来查阅了相关资料大概了解了,在这里做一下简单的 ...
- python内置常用内置方法详解
# print(locals()) # print(globals()) def func(): x = 1 y = 1 print(locals()) # 函数内部的变量 print(globals ...
- springboot成神之——springboot+mybatis+mysql搭建项目简明demo
springboot+mybatis+mysql搭建项目简明demo 项目所需目录结构 pom.xml文件配置 application.properties文件配置 MyApplication.jav ...
- Android独立交叉编译环境搭建
我们经常需将一些C/C++源码编译成本地二进制,直接在android的linux内核上运行,这是就需要进行交叉编译.由于Android的运行环境核普通Linux又区别,所以常规方式针对ARM进行交叉编 ...
- JAVA基础知识总结17(网络编程)
端口: 物理端口:IP地址 逻辑端口:用于标识进程的逻辑地址,不同进程的标识:有效端口:0~65535,其中0~1024系统使用或保留端口. JAVA中ip对象:InetAddress. import ...
- eclipse egit(分支管理 下)
在Git的分支merge中,不可能没有代码的冲突问题,特别在跟别人分工合作时.那该怎么解决? 1.新建一个conflict分支,在dev方法下添加一句 System.out.println(“Crea ...