ReaderWriterLockSlim 是 C# 中高效、轻量的读写锁实现,适合“多读少写”场景,能显著提升并发性能。它比传统的
lock或
Monitor更灵活,允许多个线程同时读,但写操作独占,且支持超时、取消和递归控制(可禁用)。
基本用法:读锁与写锁的正确加解锁
必须成对调用
EnterReadLock/
ExitReadLock或
EnterWriteLock/
ExitWriteLock,推荐用
try/finally保证释放,避免死锁。 读操作:多个线程可同时进入,调用
EnterReadLock()→ 访问共享资源 → 必须
ExitReadLock()写操作:互斥独占,调用
EnterWriteLock()→ 修改共享资源 → 必须
ExitWriteLock()不要混用:不能在持有读锁时直接升级为写锁(会死锁),需先释放读锁再申请写锁
安全写法示例:带超时和异常防护
实际项目中建议启用超时机制,防止无限等待;并始终在
finally块中释放锁:
private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
<p>public string GetData()
{
_rwLock.EnterReadLock();
try
{
return _sharedData;
}
finally
{
_rwLock.ExitReadLock();
}
}</p><p>public void UpdateData(string value)
{
if (_rwLock.TryEnterWriteLock(1000)) // 等待1秒,超时返回false
{
try
{
_sharedData = value;
}
finally
{
_rwLock.ExitWriteLock();
}
}
else
{
throw new TimeoutException("获取写锁超时");
}
}进阶控制:禁用递归、设置公平模式、响应取消
ReaderWriterLockSlim构造时可传入参数调整行为: 禁用递归:
new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion),避免同一线程重复加锁导致逻辑混乱 启用公平模式:
new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion, LockRecursionPolicy.NoRecursion)(注意:.NET 6+ 支持
new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion) { UseSpinWait = false } 配合公平队列,但真正公平需手动管理)——更准确地说,它本身不提供严格公平,但可通过 TryEnter*+ 重试 + 取消令牌模拟 配合
CancellationToken:使用
TryEnterReadLock(Int32, CancellationToken)等重载,实现可取消的等待
注意事项与常见坑
几个容易忽略却关键的细节:
务必调用Dispose()释放底层内核资源(尤其长期存活对象),建议封装为
IDisposable类型或在
using中创建(但注意:它不是设计为短生命周期对象,通常作为字段长期持有) 不要在锁内调用未知外部方法(如事件、虚方法、LINQ 查询),可能引发死锁或延长锁持有时间 读锁下禁止修改被保护的数据,否则破坏线程安全;写锁是唯一允许修改的时机 嵌套锁顺序要一致(如先读再写,所有线程都按此顺序),否则易引发死锁
基本上就这些。用好
ReaderWriterLockSlim的关键是理解“读共享、写独占”的模型,配合适当的超时和异常防护,就能在高并发读场景下兼顾安全与性能。
