标签:示例 may public 单线程 run 获取 test string success
ReaderWriterLockSlim-多线程读单线程写
注意事项
(1)线程A如果通过EnterReadLock获取到读锁(ReadLock)后,不能在持有读锁的情况下再申请获取写锁(WriteLock)
如果违反了这个规定就报如下错:
Write lock may not be acquired with read lock held. This pattern is prone to deadlocks. Please ensure that read locks are released before taking a write lock. If an upgrade is necessary, use an upgrade lock in place of the read lock.
(2)线程A如果通过EnterReadLock获取到读锁(ReadLock)后,不能在持有读锁的情况下再申请获取可升级读锁(UpgradeableReadLock)
如果违反了这个规定就报如下错:
Upgradeable lock may not be acquired with read lock held
(3)线程A如果通过EnterUpgradeableReadLock获取到可升级读锁(UpgradeableReadLockk)后,可以再持有可升级读锁的情况通过EnterWriteLock获取写锁
递归锁
递归锁:同一个线程获取到该锁后可以再获取该锁多次,不会产生死锁。
使用默认构造函数构造的ReaderWriterLockSlim是不允许锁递归的,如果一个线程已经获取到该锁后又获取该锁就会出错,如报错“Recursive upgradeable lock acquisitions not allowed in this mode”
示例如下:
解决方法:使用允许递归锁的构造方法(即new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion))构造ReaderWriterLockSlim实例
如何判断代码逻辑里会触发递归锁呢,抓住两个要点“同一线程(即ManageThreadId一样)”和“同一个锁”,在线程池里运行的时候,由于可以重用工作线程,很容易触发递归锁的问题,比如这样:线程池线程1获取到UpgradeableReadLock锁后由于后面代码里有长时等待任务,调度器可能调度线程1运行队列里的另一个同样代码的任务,这时由于代码一样线程1再次申请获取UpgradeableReadLock锁(因为上一次他已经获取到该UpgradeableReadLock锁了),就会报错了
示例代码:
static void Main() { ReaderWriterLockSlimTest(); Console.Read(); } public static void ReaderWriterLockSlimTest() { Console.WriteLine($"主线程Id : {Thread.CurrentThread.ManagedThreadId}"); // 定义共享资源 var list = new List<string>(); // 定义ReaderWriterLockSlim共享实例 //ReaderWriterLockSlim readerWriterLockSlim = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); // 允许递归锁 ReaderWriterLockSlim readerWriterLockSlim = new ReaderWriterLockSlim(); //TaskMethod0102("task1", 1, list, readerWriterLockSlim); var task1 = Task.Run(() => TaskMethod0102("task1", 1, list, readerWriterLockSlim)); var task2 = Task.Run(() => TaskMethod0102("task2", 2, list, readerWriterLockSlim)); var task3 = Task.Run(() => TaskMethod0102("task3", 3, list, readerWriterLockSlim)); //var thread1 = new Thread(() => TaskMethod0102("task1", 1, list, readerWriterLockSlim)); //var thread2 = new Thread(() => TaskMethod0102("task2", 1, list, readerWriterLockSlim)); //var thread3 = new Thread(() => TaskMethod0102("task3", 1, list, readerWriterLockSlim)); } public static string TaskMethod0102(string taskName,double seconds,List<string> list,ReaderWriterLockSlim readerWriterLockSlim) { try { Console.WriteLine($"{taskName} want to Read ,线程Id:{Thread.CurrentThread.ManagedThreadId}"); //readerWriterLockSlim.EnterReadLock(); // 尝试获取读锁 readerWriterLockSlim.EnterUpgradeableReadLock(); // 尝试获取可升级读锁 Console.WriteLine($"{taskName} success to Read ,集合总数:{(list == null ? 0 : list.Count)} ,线程Id:{Thread.CurrentThread.ManagedThreadId}"); Console.WriteLine($"{taskName} want to Write ,线程Id:{Thread.CurrentThread.ManagedThreadId}"); readerWriterLockSlim.EnterWriteLock(); Console.WriteLine($"{taskName} success to Write ,线程Id:{Thread.CurrentThread.ManagedThreadId}"); list.Add(taskName); return "OK"; } catch(Exception ex) { return "发生异常,异常信息:" + ex.Message; } finally { Console.WriteLine($"{taskName } 释放所有的锁 ,线程Id:{Thread.CurrentThread.ManagedThreadId}"); readerWriterLockSlim.ExitUpgradeableReadLock(); readerWriterLockSlim.ExitWriteLock(); } }
运行结果:
标签:示例 may public 单线程 run 获取 test string success
原文地址:https://www.cnblogs.com/tomorrow0/p/14223556.html