ReaderWriterLock 类  
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
定义支持单个写线程和多个读线程的锁。
public ref class ReaderWriterLock sealed : System::Runtime::ConstrainedExecution::CriticalFinalizerObjectpublic ref class ReaderWriterLock sealedpublic sealed class ReaderWriterLock : System.Runtime.ConstrainedExecution.CriticalFinalizerObjectpublic sealed class ReaderWriterLock[System.Runtime.InteropServices.ComVisible(true)]
public sealed class ReaderWriterLock : System.Runtime.ConstrainedExecution.CriticalFinalizerObjecttype ReaderWriterLock = class
    inherit CriticalFinalizerObjecttype ReaderWriterLock = class[<System.Runtime.InteropServices.ComVisible(true)>]
type ReaderWriterLock = class
    inherit CriticalFinalizerObjectPublic NotInheritable Class ReaderWriterLock
Inherits CriticalFinalizerObjectPublic NotInheritable Class ReaderWriterLock- 继承
- 继承
- 
				ReaderWriterLock
- 属性
示例
以下示例演示如何使用 ReaderWriterLock 来保护共享资源(名为 resource的整数值),该整数值由多个线程并发读取和独占写入。 请注意, ReaderWriterLock 是在类级别声明的,以便对所有线程可见。
// The complete code is located in the ReaderWriterLock class topic.
using System;
using System.Threading;
public class Example
{
   static ReaderWriterLock rwl = new ReaderWriterLock();
   // Define the shared resource protected by the ReaderWriterLock.
   static int resource = 0;
   const int numThreads = 26;
   static bool running = true;
   // Statistics.
   static int readerTimeouts = 0;
   static int writerTimeouts = 0;
   static int reads = 0;
   static int writes = 0;
   public static void Main()
   {
      // Start a series of threads to randomly read from and
      // write to the shared resource.
      Thread[] t = new Thread[numThreads];
      for (int i = 0; i < numThreads; i++){
         t[i] = new Thread(new ThreadStart(ThreadProc));
         t[i].Name = new String((char)(i + 65), 1);
         t[i].Start();
         if (i > 10)
            Thread.Sleep(300);
      }
      // Tell the threads to shut down and wait until they all finish.
      running = false;
      for (int i = 0; i < numThreads; i++)
         t[i].Join();
      // Display statistics.
      Console.WriteLine("\n{0} reads, {1} writes, {2} reader time-outs, {3} writer time-outs.",
            reads, writes, readerTimeouts, writerTimeouts);
      Console.Write("Press ENTER to exit... ");
      Console.ReadLine();
   }
   static void ThreadProc()
   {
      Random rnd = new Random();
      // Randomly select a way for the thread to read and write from the shared
      // resource.
      while (running) {
         double action = rnd.NextDouble();
         if (action < .8)
            ReadFromResource(10);
         else if (action < .81)
            ReleaseRestore(rnd, 50);
         else if (action < .90)
            UpgradeDowngrade(rnd, 100);
         else
            WriteToResource(rnd, 100);
      }
   }
   // Request and release a reader lock, and handle time-outs.
   static void ReadFromResource(int timeOut)
   {
      try {
         rwl.AcquireReaderLock(timeOut);
         try {
            // It is safe for this thread to read from the shared resource.
            Display("reads resource value " + resource);
            Interlocked.Increment(ref reads);
         }
         finally {
            // Ensure that the lock is released.
            rwl.ReleaseReaderLock();
         }
      }
      catch (ApplicationException) {
         // The reader lock request timed out.
         Interlocked.Increment(ref readerTimeouts);
      }
   }
   // Request and release the writer lock, and handle time-outs.
   static void WriteToResource(Random rnd, int timeOut)
   {
      try {
         rwl.AcquireWriterLock(timeOut);
         try {
            // It's safe for this thread to access from the shared resource.
            resource = rnd.Next(500);
            Display("writes resource value " + resource);
            Interlocked.Increment(ref writes);
         }
         finally {
            // Ensure that the lock is released.
            rwl.ReleaseWriterLock();
         }
      }
      catch (ApplicationException) {
         // The writer lock request timed out.
         Interlocked.Increment(ref writerTimeouts);
      }
   }
   // Requests a reader lock, upgrades the reader lock to the writer
   // lock, and downgrades it to a reader lock again.
   static void UpgradeDowngrade(Random rnd, int timeOut)
   {
      try {
         rwl.AcquireReaderLock(timeOut);
         try {
            // It's safe for this thread to read from the shared resource.
            Display("reads resource value " + resource);
            Interlocked.Increment(ref reads);
            // To write to the resource, either release the reader lock and
            // request the writer lock, or upgrade the reader lock. Upgrading
            // the reader lock puts the thread in the write queue, behind any
            // other threads that might be waiting for the writer lock.
            try {
               LockCookie lc = rwl.UpgradeToWriterLock(timeOut);
               try {
                  // It's safe for this thread to read or write from the shared resource.
                  resource = rnd.Next(500);
                  Display("writes resource value " + resource);
                  Interlocked.Increment(ref writes);
               }
               finally {
                  // Ensure that the lock is released.
                  rwl.DowngradeFromWriterLock(ref lc);
               }
            }
            catch (ApplicationException) {
               // The upgrade request timed out.
               Interlocked.Increment(ref writerTimeouts);
            }
            // If the lock was downgraded, it's still safe to read from the resource.
            Display("reads resource value " + resource);
            Interlocked.Increment(ref reads);
         }
         finally {
            // Ensure that the lock is released.
            rwl.ReleaseReaderLock();
         }
      }
      catch (ApplicationException) {
         // The reader lock request timed out.
         Interlocked.Increment(ref readerTimeouts);
      }
   }
   // Release all locks and later restores the lock state.
   // Uses sequence numbers to determine whether another thread has
   // obtained a writer lock since this thread last accessed the resource.
   static void ReleaseRestore(Random rnd, int timeOut)
   {
      int lastWriter;
      try {
         rwl.AcquireReaderLock(timeOut);
         try {
            // It's safe for this thread to read from the shared resource,
            // so read and cache the resource value.
            int resourceValue = resource;     // Cache the resource value.
            Display("reads resource value " + resourceValue);
            Interlocked.Increment(ref reads);
            // Save the current writer sequence number.
            lastWriter = rwl.WriterSeqNum;
            // Release the lock and save a cookie so the lock can be restored later.
            LockCookie lc = rwl.ReleaseLock();
            // Wait for a random interval and then restore the previous state of the lock.
            Thread.Sleep(rnd.Next(250));
            rwl.RestoreLock(ref lc);
            // Check whether other threads obtained the writer lock in the interval.
            // If not, then the cached value of the resource is still valid.
            if (rwl.AnyWritersSince(lastWriter)) {
               resourceValue = resource;
               Interlocked.Increment(ref reads);
               Display("resource has changed " + resourceValue);
            }
            else {
               Display("resource has not changed " + resourceValue);
            }
         }
         finally {
            // Ensure that the lock is released.
            rwl.ReleaseReaderLock();
         }
      }
      catch (ApplicationException) {
         // The reader lock request timed out.
         Interlocked.Increment(ref readerTimeouts);
      }
   }
   // Helper method briefly displays the most recent thread action.
   static void Display(string msg)
   {
      Console.Write("Thread {0} {1}.       \r", Thread.CurrentThread.Name, msg);
   }
}
' The complete code is located in the ReaderWriterLock class topic.
Imports System.Threading
Public Module Example
   Private rwl As New ReaderWriterLock()
   ' Define the shared resource protected by the ReaderWriterLock.
   Private resource As Integer = 0
   Const numThreads As Integer = 26
   Private running As Boolean = True
   
   ' Statistics.
   Private readerTimeouts As Integer = 0
   Private writerTimeouts As Integer = 0
   Private reads As Integer = 0
   Private writes As Integer = 0
  
   Public Sub Main()
      ' Start a series of threads to randomly read from and
      ' write to the shared resource.
      Dim t(numThreads - 1) As Thread
      Dim i As Integer
      For i = 0 To numThreads - 1
         t(i) = New Thread(New ThreadStart(AddressOf ThreadProc))
         t(i).Name = Chr(i + 65)
         t(i).Start()
         If i > 10 Then
            Thread.Sleep(300)
         End If
      Next
      ' Tell the threads to shut down and wait until they all finish.
      running = False
      For i = 0 To numThreads - 1
         t(i).Join()
      Next
      
      ' Display statistics.
      Console.WriteLine(vbCrLf & "{0} reads, {1} writes, {2} reader time-outs, {3} writer time-outs.",
                        reads, writes, readerTimeouts, writerTimeouts)
      Console.Write("Press ENTER to exit... ")
      Console.ReadLine()
   End Sub
   Sub ThreadProc()
      Dim rnd As New Random
      ' Randomly select a way for the thread to read and write from the shared
      ' resource.
      While running
         Dim action As Double = rnd.NextDouble()
         If action < 0.8 Then
            ReadFromResource(10)
         ElseIf action < 0.81 Then
            ReleaseRestore(rnd, 50)
         ElseIf action < 0.9 Then
            UpgradeDowngrade(rnd, 100)
         Else
            WriteToResource(rnd, 100)
         End If
      End While
   End Sub
    
   ' Request and release a reader lock, and handle time-outs.
   Sub ReadFromResource(timeOut As Integer)
      Try
         rwl.AcquireReaderLock(timeOut)
         Try
            ' It's safe for this thread to read from the shared resource.
            Display("reads resource value " & resource)
            Interlocked.Increment(reads)
         Finally
            ' Ensure that the lock is released.
            rwl.ReleaseReaderLock()
         End Try
      Catch ex As ApplicationException
         ' The reader lock request timed out.
         Interlocked.Increment(readerTimeouts)
      End Try
   End Sub
   ' Request and release the writer lock, and handle time-outs.
   Sub WriteToResource(rnd As Random, timeOut As Integer)
      Try
         rwl.AcquireWriterLock(timeOut)
         Try
            ' It's safe for this thread to read or write from the shared resource.
            resource = rnd.Next(500)
            Display("writes resource value " & resource)
            Interlocked.Increment(writes)
         Finally
            ' Ensure that the lock is released.
            rwl.ReleaseWriterLock()
         End Try
      Catch ex As ApplicationException
         ' The writer lock request timed out.
         Interlocked.Increment(writerTimeouts)
      End Try
   End Sub
   ' Requests a reader lock, upgrades the reader lock to the writer
   ' lock, and downgrades it to a reader lock again.
   Sub UpgradeDowngrade(rnd As Random, timeOut As Integer)
      Try
         rwl.AcquireReaderLock(timeOut)
         Try
            ' It's safe for this thread to read from the shared resource.
            Display("reads resource value " & resource)
            Interlocked.Increment(reads)
            
            ' To write to the resource, either release the reader lock and
            ' request the writer lock, or upgrade the reader lock. Upgrading
            ' the reader lock puts the thread in the write queue, behind any
            ' other threads that might be waiting for the writer lock.
            Try
               Dim lc As LockCookie = rwl.UpgradeToWriterLock(timeOut)
               Try
                  ' It's safe for this thread to read or write from the shared resource.
                  resource = rnd.Next(500)
                  Display("writes resource value " & resource)
                  Interlocked.Increment(writes)
               Finally
                  ' Ensure that the lock is released.
                  rwl.DowngradeFromWriterLock(lc)
               End Try
            Catch ex As ApplicationException
               ' The upgrade request timed out.
               Interlocked.Increment(writerTimeouts)
            End Try
            
            ' If the lock was downgraded, it's still safe to read from the resource.
            Display("reads resource value " & resource)
            Interlocked.Increment(reads)
         Finally
            ' Ensure that the lock is released.
            rwl.ReleaseReaderLock()
         End Try
      Catch ex As ApplicationException
         ' The reader lock request timed out.
         Interlocked.Increment(readerTimeouts)
      End Try
   End Sub
   ' Release all locks and later restores the lock state.
   ' Uses sequence numbers to determine whether another thread has
   ' obtained a writer lock since this thread last accessed the resource.
   Sub ReleaseRestore(rnd As Random ,timeOut As Integer)
      Dim lastWriter As Integer
      
      Try
         rwl.AcquireReaderLock(timeOut)
         Try
            ' It's safe for this thread to read from the shared resource,
            ' so read and cache the resource value.
            Dim resourceValue As Integer = resource
            Display("reads resource value " & resourceValue)
            Interlocked.Increment(reads)
            
            ' Save the current writer sequence number.
            lastWriter = rwl.WriterSeqNum
            
            ' Release the lock and save a cookie so the lock can be restored later.
            Dim lc As LockCookie = rwl.ReleaseLock()
            
            ' Wait for a random interval and then restore the previous state of the lock.
            Thread.Sleep(rnd.Next(250))
            rwl.RestoreLock(lc)
           
            ' Check whether other threads obtained the writer lock in the interval.
            ' If not, then the cached value of the resource is still valid.
            If rwl.AnyWritersSince(lastWriter) Then
               resourceValue = resource
               Interlocked.Increment(reads)
               Display("resource has changed " & resourceValue)
            Else
               Display("resource has not changed " & resourceValue)
            End If
         Finally
            ' Ensure that the lock is released.
            rwl.ReleaseReaderLock()
         End Try
      Catch ex As ApplicationException
         ' The reader lock request timed out.
         Interlocked.Increment(readerTimeouts)
      End Try
   End Sub
   ' Helper method briefly displays the most recent thread action.
   Sub Display(msg As String)
      Console.Write("Thread {0} {1}.       " & vbCr, Thread.CurrentThread.Name, msg)
   End Sub
End Module
注解
重要
.NET Framework有两个读取器-写入器锁和 ReaderWriterLockSlimReaderWriterLock。 建议对所有新开发的项目使用 ReaderWriterLockSlim。 虽然 ReaderWriterLockSlim 类似于 ReaderWriterLock,但不同之处在于,前者简化了递归规则以及锁状态的升级和降级规则。 ReaderWriterLockSlim 避免了许多潜在的死锁情况。 另外,ReaderWriterLockSlim 的性能显著优于 ReaderWriterLock。
              ReaderWriterLock 用于同步对资源的访问。 在任何给定时间,它都允许对多个线程进行并发读取访问,或对单个线程进行写入访问。 在资源不经常更改的情况下, ReaderWriterLock 与简单的一次锁定(例如 ) Monitor相比,提供更好的吞吐量。
              ReaderWriterLock 在大多数访问是读取,而写入不频繁且持续时间短的情况下,效果最佳。 多个读取器交替使用单个编写器,因此读取器和编写器都不会长时间被阻止。
注意
长时间保留读取器锁或编写器锁会耗尽其他线程。 为了获得最佳性能,请考虑重新调整应用程序以最大程度地减少写入持续时间。
线程可以同时持有读取器锁或编写器锁,但不能同时持有两者。 可以使用 UpgradeToWriterLock 和 DowngradeFromWriterLock,而不是为了获取编写器锁而释放读取器锁。
递归锁请求会增加锁上的锁计数。
读取器和编写器分别排队。 当线程释放编写器锁时,此时在读取器队列中等待的所有线程都被授予读取器锁;释放所有这些读取器锁后,写入器队列中等待的下一个线程(如果有)将被授予编写器锁,依此排序。 换句话说, ReaderWriterLock 在读者集合和一个编写器之间交替。
当编写器队列中的线程正在等待释放活动读取器锁时,请求新读取器锁的线程将累积在读取器队列中。 他们的请求未获得授权,即使他们可以与现有读者锁持有者共享并发访问权限;这有助于保护编写器免受读取器的无限期阻塞。
获取锁定 ReaderWriterLock 的大多数方法都接受超时值。 使用超时来避免应用程序中出现死锁。 例如,线程可能会获取一个资源的编写器锁,然后请求另一个资源的读取器锁;同时,另一个线程可能会获取第二个资源的编写器锁,并在第一个资源上请求读取器锁。 除非使用超时,否则线程死锁。
如果超时间隔过期且未授予锁定请求,则 方法通过引发 ApplicationException将控制权返回到调用线程。 线程可以捕获此异常并确定接下来要执行的操作。
超时以毫秒表示。 如果使用 System.TimeSpan 指定超时,则使用的值是 表示 TimeSpan的整毫秒总数。 下表显示了有效的超时值(以毫秒为单位)。
| “值” | 说明 | 
|---|---|
| -1 | 线程将等待,直到获取锁,而不管它需要多长时间。 对于指定整数超时的方法,可以使用 常量 Infinite 。 | 
| 0 | 线程不会等待获取锁。 如果无法立即获取锁,方法将返回。 | 
| >0 | 要等待的毫秒数。 | 
除 -1 外,不允许使用负超时值。 如果指定除 -1 以外的负整数,则改用零的超时值。 (也就是说,如果无法立即获取锁,则方法返回而不等待。) 如果指定 TimeSpan 表示除 -1 以外的负数毫秒的 , ArgumentOutOfRangeException 则会引发。
构造函数
| ReaderWriterLock() | 初始化 ReaderWriterLock 类的新实例。 | 
属性
| IsReaderLockHeld | 获取一个值,该值指示当前线程是否持有读线程锁。 | 
| IsWriterLockHeld | 获取一个值,该值指示当前线程是否持有写线程锁。 | 
| WriterSeqNum | 获取当前序列号。 | 
方法
| AcquireReaderLock(Int32) | 使用一个 Int32 超时值获取读线程锁。 | 
| AcquireReaderLock(TimeSpan) | 使用一个 TimeSpan 超时值获取读线程锁。 | 
| AcquireWriterLock(Int32) | 使用一个 Int32 超时值获取写线程锁。 | 
| AcquireWriterLock(TimeSpan) | 使用一个 TimeSpan 超时值获取写线程锁。 | 
| AnyWritersSince(Int32) | 指示获取序列号之后是否已将写线程锁授予某个线程。 | 
| DowngradeFromWriterLock(LockCookie) | 将线程的锁状态还原为调用 UpgradeToWriterLock(Int32) 前的状态。 | 
| Equals(Object) | 确定指定对象是否等于当前对象。(继承自 Object) | 
| Finalize() | 确保垃圾回收器回收 ReaderWriterLock 对象时释放资源并执行其他清理操作。 | 
| GetHashCode() | 作为默认哈希函数。(继承自 Object) | 
| GetType() | 获取当前实例的 Type。(继承自 Object) | 
| MemberwiseClone() | 创建当前 Object 的浅表副本。(继承自 Object) | 
| ReleaseLock() | 释放锁,不管线程获取锁的次数如何。 | 
| ReleaseReaderLock() | 减少锁计数。 | 
| ReleaseWriterLock() | 减少写线程锁上的锁计数。 | 
| RestoreLock(LockCookie) | 将线程的锁状态还原为调用 ReleaseLock() 前的状态。 | 
| ToString() | 返回表示当前对象的字符串。(继承自 Object) | 
| UpgradeToWriterLock(Int32) | 使用一个 Int32 超时值将读线程锁升级为写线程锁。 | 
| UpgradeToWriterLock(TimeSpan) | 使用一个  | 
适用于
线程安全性
此类型是线程安全的。