[.net 多线程 ]ReaderWriterLock

ReaderWriterLock 用于同步对资源的访问。在任一特定时刻,它允许多个线程同时进行读访问,或者允许单个线程进行写访问。在资源不经常发生更改的情况下,ReaderWriterLock 所提供的吞吐量比简单的一次只允许一个线程的锁(如 Monitor)更高。

在多数访问为读访问,而写访问频率较低、持续时间也比较短的情况下,ReaderWriterLock 的性能最好。多个读线程与单个写线程交替进行操作,所以读线程和写线程都不会长时间阻止。

注意 
长时间持有读线程锁或写线程锁会使其他线程发生饥饿 (starve)。为了得到最好的性能,需要考虑重新构造应用程序以将写访问的持续时间减少到最小。

一个线程可以持有读线程锁或写线程锁,但是不能同时持有两者。若要获取写线程锁,请使用 UpgradeToWriterLock 和 DowngradeFromWriterLock,而不要通过释放读线程锁的方式获取。

递归锁请求会增加锁上的锁计数。

读线程和写线程将分别排入各自的队列。当线程释放写线程锁时,此刻读线程队列中的所有等待线程都将被授予读线程锁;当已释放所有读线程锁时,写线程队列中处于等待状态的下一个线程(如果存在)将被授予写线程锁,依此类推。换句话说,ReaderWriterLock 在一组读线程和一个写线程之间交替进行操作。

当写线程队列中有一个线程在等待活动读线程锁被释放时,请求新的读线程锁的线程会排入读线程队列。即使它们能和现有的阅读器锁持有者共享并发访问,也不会给它们的请求授予权限;这有助于防止编写器被阅读器无限期阻止。

大多数在 ReaderWriterLock 上获取锁的方法都采用超时值。使用超时可以避免应用程序中出现死锁。例如,某个线程可能获取了一个资源上的写线程锁,然后请求第二个资源上的读线程锁;同时,另一个线程获取了第二个资源上的写线程锁,并请求第一个资源上的读线程锁。如果不使用超时,这两个线程将出现死锁。

如果超时间隔过期并且没有授予锁请求,则此方法通过引发 ApplicationException 将控制返回给调用线程。线程可以捕捉此异常并确定下一步要进行的操作。

  1 static void Main(string[] args)
  2         {
  3             Dictionary<int, string> dic = new Dictionary<int, string>();
  4             ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
  5             Task.Factory.StartNew(() =>
  6             {
  7                 int key = 0;
  8                 while (key <= 1000)
  9                 {
 10                     Thread.Sleep(10);
 11                     string info = $"写线程:{DateTime.Now.ToString("hhMMss-fff")}";
 12                     if (lockSlim.TryEnterWriteLock(20))
 13                     {
 14                         try
 15                         {
 16                             dic.Add(key++, info);
 17                             Console.WriteLine(info);
 18                         }
 19                         catch (Exception ex)
 20                         {
 21                             ;
 22                         }
 23                         finally
 24                         {
 25                             Console.WriteLine($"释放 {info}");
 26                             lockSlim.ExitWriteLock();
 27                         }
 28                     }
 29                 }
 30             });
 31             Task.Factory.StartNew(() =>
 32             {
 33                 while (true)
 34                 {
 35                     Thread.Sleep(100);
 36                     int key = 0;
 37                     if (lockSlim.TryEnterReadLock(20))
 38                     {
 39                         try
 40                         {
 41                             while (key < dic.Count)
 42                             {
 43                                 Console.WriteLine($"读线程1:{dic[key++]}");
 44                             }
 45                         }
 46                         catch (Exception ex)
 47                         {
 48                             ;
 49                         }
 50                         finally
 51                         {
 52                             lockSlim.ExitReadLock();
 53                         }
 54                     }
 55                 }
 56             });
 57             Task.Factory.StartNew(() =>
 58             {
 59                 while (true)
 60                 {
 61                     Thread.Sleep(100);
 62                     int key = 0;
 63                     if (lockSlim.TryEnterReadLock(20))
 64                     {
 65                         try
 66                         {
 67                             while (key < dic.Count)
 68                             {
 69                                 Console.WriteLine($"读线程2:{dic[key++]}");
 70                             }
 71                         }
 72                         catch (Exception ex)
 73                         {
 74                             ;
 75                         }
 76                         finally
 77                         {
 78                             lockSlim.ExitReadLock();
 79                         }
 80                     }
 81                 }
 82             });
 83             Task.Factory.StartNew(() =>
 84             {
 85                 while (true)
 86                 {
 87                     Thread.Sleep(100);
 88                     int key = 0;
 89                     if (lockSlim.TryEnterReadLock(20))
 90                     {
 91                         try
 92                         {
 93                             while (key < dic.Count)
 94                             {
 95                                 Console.WriteLine($"读线程3:{dic[key++]}");
 96                             }
 97                         }
 98                         catch (Exception ex)
 99                         {
100                             ;
101                         }
102                         finally
103                         {
104                             lockSlim.ExitReadLock();
105                         }
106                     }
107                 }
108             });
109             Task.Factory.StartNew(() =>
110             {
111                 while (true)
112                 {
113                     Thread.Sleep(100);
114                     int key = 0;
115                     if (lockSlim.TryEnterReadLock(20))
116                     {
117                         try
118                         {
119                             while (key < dic.Count)
120                             {
121                                 Console.WriteLine($"读线程4:{dic[key++]}");
122                             }
123                         }
124                         catch (Exception ex)
125                         {
126                             ;
127                         }
128                         finally
129                         {
130                             lockSlim.ExitReadLock();
131                         }
132                     }
133                 }
134             });
135             Console.ReadKey();
136         }
View Code

.NET 同步与异步之锁(ReaderWriterLockSlim)(八)

c#线程同步系列(二) c#中ReaderWriterLock的使用

读写锁ReaderWriterLockSlim

原文地址:https://www.cnblogs.com/deepminer/p/9053933.html