1、如题:资源可能是很少次的写入,但是,会经常读写。如果使用lock,读一次,锁定一次资源;写一次,锁定一次资源。读取资源相对写入资源消耗会小一些,但是多次去读的话,每次锁定一次,会造成资源的浪费。
.Net FrameWork为我们提供了更好的解决方式,ReaderWriterLockSlim,这个类提供了一个锁定功能,如果没有写入器锁定资源,就允许多个读取器访问资源,但只能有一个写入器锁定该资源。
1》获取读取锁和写入锁的方式:
读取锁 | 写入锁 | |
阻塞 | EnterReadLock() | EnterWriterLock() |
不阻塞 | TryEnterReadLock() | TryEnterWriterLock() |
什么情况下,获取写入锁定状态,而不用释放读取锁定?
如果是先读取资源,之后写入资源,就可以使用 EnterUpgradeableReadLock或者TryEnterUpgradeableReadLock方法获得可升级的锁定。
有了这个锁定,就可以获得写入锁定,而无需释放读取锁定。
2》属性
属性 | 说明 |
CurrentReadCount | 获取以夺取模式进入锁定唯一线程总数 |
WaitingReadCount | 获取等待进入读取模式锁定状态的线程总数 |
WaitingUpgradeCount | 获取等待进入可升级模式锁定状态的总数 |
WaitingWriteCount | 获取等待进入写入模式锁定状态的线程总数 |
场景:出板报和看板报,学校里我们出板报时,是由出板报的人员独自锁定了板报,进行作业。而到了看板报的时候,又可以有很多人同时看。我感觉这个例子挺适合。代码如下:
class Program
{
static void Main(string[] args)
{
ReaderWriterDemo();
Console.WriteLine("game over");
Console.ReadLine();
}
#region
static void ReaderWriterDemo()
{
ReaderWriterLockSlim reader = new ReaderWriterLockSlim();
//场景,出板报,就是一个例子,画板报的时候,需要一个写入器锁定资源,但是读取的时候就可以多个线程同时读取,
//假如读取板报的人比较多,就得先看完,走了之后,剩下的才能看,也就相当源一个读取锁定了。
var taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);
var tasks = new Task[6];
var w1 = new ReaderWriteLockDemo("w1");
var w2 = new ReaderWriteLockDemo("w2");
var r1 = new ReaderWriteLockDemo("r1");
var r2 = new ReaderWriteLockDemo("r2");
var r3 = new ReaderWriteLockDemo("r3");
var r4 = new ReaderWriteLockDemo("r4");
tasks[0] = taskFactory.StartNew(w1.Writer);
tasks[1] = taskFactory.StartNew(r1.Reader);
tasks[2] = taskFactory.StartNew(r2.Reader);
tasks[3] = taskFactory.StartNew(w2.Writer);
tasks[4] = taskFactory.StartNew(r3.Reader);
tasks[5] = taskFactory.StartNew(r4.Reader);
Task.WaitAll(tasks);
}
#endregion
}
public class ReaderWriteLockDemo
{
public static List<int> list = new List<int> { 5, 2, 6, 3, 5, 7, 7, 8, 10 };
//声明一个读写对象。
static ReaderWriterLockSlim _rwl = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
private string _name;
public ReaderWriteLockDemo(string name)
{
this._name = name;
}
/// <summary>
/// 看板报
/// </summary>
public void Reader()
{
try
{
_rwl.EnterReadLock();
for(int i=0;i<list.Count;i++)
{
WriteLine($" {this._name} 正在看 {list[i]} 内容 ");
Task.Delay(40).Wait();
}
}
finally
{
_rwl.ExitReadLock();
}
}
/// <summary>
/// 画板报
/// </summary>
public void Writer()
{
try
{
while(!_rwl.TryEnterWriteLock(50))
{
WriteLine($" 出板报人员{this._name} 等待写版本锁定");
WriteLine($" 当前的读者还有:{_rwl.WaitingReadCount}");
}
WriteLine($"{this._name} 写板报人员获得了锁定 ");
for(int i=0;i<list.Count;i++)
{
list[i]++;
Task.Delay(50).Wait();
}
WriteLine($"{this._name} 写完了");
}
finally
{
_rwl.ExitWriteLock();
}
}
}
每天的点点滴滴,可能不尽如人意,请不吝赐教。