.NET Framework Class Library
ReaderWriterLock Class

Defines a lock that supports single writers and multiple readers.

Namespace:  System.Threading
Assembly:  mscorlib (in mscorlib.dll)
Syntax

Visual Basic (Declaration)
<ComVisibleAttribute(True)> _
<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization := True,  _
    ExternalThreading := True)> _
Public NotInheritable Class ReaderWriterLock _
    Inherits CriticalFinalizerObject
Visual Basic (Usage)
Dim instance As ReaderWriterLock
C#
[ComVisibleAttribute(true)]
[HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, 
    ExternalThreading = true)]
public sealed class ReaderWriterLock : CriticalFinalizerObject
Visual C++
[ComVisibleAttribute(true)]
[HostProtectionAttribute(SecurityAction::LinkDemand, Synchronization = true, 
    ExternalThreading = true)]
public ref class ReaderWriterLock sealed : public CriticalFinalizerObject
JScript
public final class ReaderWriterLock extends CriticalFinalizerObject
Remarks

NoteNote:

The HostProtectionAttribute attribute applied to this type or member has the following Resources property value: Synchronization | ExternalThreading. The HostProtectionAttribute does not affect desktop applications (which are typically started by double-clicking an icon, typing a command, or entering a URL in a browser). For more information, see the HostProtectionAttribute class or SQL Server Programming and Host Protection Attributes.

Important noteImportant Note:

The .NET Framework has two reader-writer locks, ReaderWriterLockSlim and ReaderWriterLock. ReaderWriterLockSlim is recommended for all new development. ReaderWriterLockSlim is similar to ReaderWriterLock, but it has simplified rules for recursion and for upgrading and downgrading lock state. ReaderWriterLockSlim avoids many cases of potential deadlock. In addition, the performance of ReaderWriterLockSlim is significantly better than ReaderWriterLock.

ReaderWriterLock is used to synchronize access to a resource. At any given time, it allows either concurrent read access for multiple threads, or write access for a single thread. In a situation where a resource is changed infrequently, a ReaderWriterLock provides better throughput than a simple one-at-a-time lock, such as Monitor.

ReaderWriterLock works best where most accesses are reads, while writes are infrequent and of short duration. Multiple readers alternate with single writers, so that neither readers nor writers are blocked for long periods.

NoteNote:

Holding reader locks or writer locks for long periods will starve other threads. For best performance, consider restructuring your application to minimize the duration of writes.

A thread can hold a reader lock or a writer lock, but not both at the same time. Instead of releasing a reader lock in order to acquire the writer lock, you can use UpgradeToWriterLock and DowngradeFromWriterLock.

Recursive lock requests increase the lock count on a lock.

Readers and writers are queued separately. When a thread releases the writer lock, all threads waiting in the reader queue at that instant are granted reader locks; when all of those reader locks have been released, the next thread waiting in the writer queue, if any, is granted the writer lock, and so on. In other words, ReaderWriterLock alternates between a collection of readers, and one writer.

While a thread in the writer queue is waiting for active reader locks to be released, threads requesting new reader locks accumulate in the reader queue. Their requests are not granted, even though they could share concurrent access with existing reader-lock holders; this helps protect writers against indefinite blockage by readers.

Most methods for acquiring locks on a ReaderWriterLock accept time-out values. Use time-outs to avoid deadlocks in your application. For example, a thread might acquire the writer lock on one resource and then request a reader lock on a second resource; in the meantime, another thread might acquire the writer lock on the second resource, and request a reader lock on the first. Unless time-outs are used, the threads deadlock.

If the time-out interval expires and the lock request has not been granted, the method returns control to the calling thread by throwing an ApplicationException. A thread can catch this exception and determine what action to take next.

Time-outs are expressed in milliseconds. If you use a System..::.TimeSpan to specify the time-out, the value used is the total number of whole milliseconds represented by the TimeSpan. The following table shows the valid time-out values in milliseconds.

Value

Description

-1

The thread waits until the lock is acquired, regardless of how long it takes. For methods that specify integer time-outs, the constant Infinite can be used.

0

The thread does not wait to acquire the lock. If the lock cannot be acquired immediately, the method returns.

>0

The number of milliseconds to wait.

With the exception of -1, negative time-out values are not allowed. If you specify a negative integer other than -1, a time-out value of zero is used instead. (That is, the method returns without waiting, if the lock cannot be acquired immediately.) If you specify a TimeSpan that represents a negative number of milliseconds other than -1, ArgumentOutOfRangeException is thrown.

Examples

The following example demonstrates how to use a ReaderWriterLock to protect a shared resource that is read concurrently and written exclusively by multiple threads.

Visual Basic
' This example shows a ReaderWriterLock protecting a shared
' resource that is read concurrently and written exclusively
' by multiple threads.

' The complete code is located in the ReaderWriterLock
' class topic.
Imports System
Imports System.Threading
Imports Microsoft.VisualBasic

Public Class Test
    ' Declaring the ReaderWriterLock at the class level
    ' makes it visible to all threads.
    Private Shared rwl As New ReaderWriterLock()
    ' For this example, the shared resource protected by the
    ' ReaderWriterLock is just an integer.
    Private Shared resource As Integer = 0

    Const numThreads As Integer = 26
    Private Shared running As Boolean = True
    Private Shared rnd As New Random()

    ' Statistics.
    Private Shared readerTimeouts As Integer = 0
    Private Shared writerTimeouts As Integer = 0
    Private Shared reads As Integer = 0
    Private Shared writes As Integer = 0

    <MTAThread> _
    Public Shared Sub Main(args() As String)
        ' Start a series of threads. Each thread randomly
        ' performs reads and writes on the shared resource.
        Dim t(numThreads) 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 i 

        ' Tell the threads to shut down, then wait until they all
        ' finish.
        running = False
        For i = 0 To numThreads - 1
            t(i).Join()
        Next i

        ' Display statistics.
        Console.WriteLine(vbCrLf & "{0} reads, {1} writes, {2} reader time-outs, {3} writer time-outs.", reads, writes, readerTimeouts, writerTimeouts)
        Console.WriteLine("Press ENTER to exit.")
        Console.ReadLine()
    End Sub 'Main


    Shared Sub ThreadProc()
        ' As long as a thread runs, it randomly selects
        ' various ways to read and write from the shared 
        ' resource. Each of the methods demonstrates one 
        ' or more features of ReaderWriterLock.
        While running
            Dim action As Double = rnd.NextDouble()
            If action < 0.8 Then
                ReadFromResource(10)
            ElseIf action < 0.81 Then
                ReleaseRestore(50)
            ElseIf action < 0.9 Then
                UpgradeDowngrade(100)
            Else
                WriteToResource(100)
            End If
        End While
    End Sub 'ThreadProc

    ' Shows how to request and release a reader lock, and
    ' how to handle time-outs.
    Shared Sub ReadFromResource(timeOut As Integer)
        Try
            rwl.AcquireReaderLock(timeOut)
            Try
                ' It is 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 'ReadFromResource

    ' Shows how to request and release the writer lock, and
    ' how to handle time-outs.
    Shared Sub WriteToResource(timeOut As Integer)
        Try
            rwl.AcquireWriterLock(timeOut)
            Try
                ' It is 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 'WriteToResource

    ' Shows how to request a reader lock, upgrade the
    ' reader lock to the writer lock, and downgrade to a
    ' reader lock again.
    Shared Sub UpgradeDowngrade(timeOut As Integer)
        Try
            rwl.AcquireReaderLock(timeOut)
            Try
                ' It is safe for this thread to read from
                ' the shared resource.
                Display("reads resource value " & resource)
                Interlocked.Increment(reads)

                ' If it is necessary to write to the resource,
                ' you must either release the reader lock and 
                ' then request the writer lock, or upgrade the
                ' reader lock. Note that 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 is 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

                ' When the lock has been downgraded, it is 
                ' 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 'UpgradeDowngrade

    ' Shows how to release all locks and later restore
    ' the lock state. Shows how to use sequence numbers
    ' to determine whether another thread has obtained
    ' a writer lock since this thread last accessed the
    ' resource.
    Shared Sub ReleaseRestore(timeOut As Integer)
        Dim lastWriter As Integer

        Try
            rwl.AcquireReaderLock(timeOut)
            Try
                ' It is safe for this thread to read from
                ' the shared resource. Cache the value. (You
                ' might do this if reading the resource is
                ' an expensive operation.)
                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 (up to a 
                ' quarter of a second), and then restore
                ' the previous state of the lock. Note that
                ' there is no time-out on the Restore method.
                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 'ReleaseRestore

    ' Helper method briefly displays the most recent
    ' thread action. Comment out calls to Display to 
    ' get a better idea of throughput.
    Shared Sub Display(msg As String)
        Console.Write("Thread {0} {1}.       " & vbCr, Thread.CurrentThread.Name, msg)
    End Sub 'Display
End Class 'Test 
C#
// This example shows a ReaderWriterLock protecting a shared
// resource that is read concurrently and written exclusively
// by multiple threads.

// The complete code is located in the ReaderWriterLock
// class topic.
using System;
using System.Threading;

public class Test
{
    // Declaring the ReaderWriterLock at the class level
    // makes it visible to all threads.
    static ReaderWriterLock rwl = new ReaderWriterLock();
    // For this example, the shared resource protected by the
    // ReaderWriterLock is just an integer.
    static int resource = 0;

    const int numThreads = 26;
    static bool running = true;
    static Random rnd = new Random();

    // Statistics.
    static int readerTimeouts = 0;
    static int writerTimeouts = 0;
    static int reads = 0;
    static int writes = 0;

    public static void Main(string[] args)
    {
        // Start a series of threads. Each thread randomly
        // performs reads and writes on 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(Convert.ToChar(i + 65), 1);
            t[i].Start();
            if (i > 10)
                Thread.Sleep(300);
        }

        // Tell the threads to shut down, then wait until they all
        // finish.
        running = false;
        for (int i = 0; i < numThreads; i++)
        {
            t[i].Join();
        }

        // Display statistics.
        Console.WriteLine("\r\n{0} reads, {1} writes, {2} reader time-outs, {3} writer time-outs.",
            reads, writes, readerTimeouts, writerTimeouts);
        Console.WriteLine("Press ENTER to exit.");
        Console.ReadLine();
    }

    static void ThreadProc()
    {
        // As long as a thread runs, it randomly selects
        // various ways to read and write from the shared 
        // resource. Each of the methods demonstrates one 
        // or more features of ReaderWriterLock.
        while (running)
        {
            double action = rnd.NextDouble();
            if (action < .8)
                ReadFromResource(10);
            else if (action < .81)
                ReleaseRestore(50);
            else if (action < .90)
                UpgradeDowngrade(100);
            else
                WriteToResource(100);
        }
    }

    // Shows how to request and release a reader lock, and
    // how to 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);
        }
    }

    // Shows how to request and release the writer lock, and
    // how to handle time-outs.
    static void WriteToResource(int timeOut)
    {
        try
        {
            rwl.AcquireWriterLock(timeOut);
            try
            {
                // It is 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.ReleaseWriterLock();
            }
        }
        catch (ApplicationException)
        {
            // The writer lock request timed out.
            Interlocked.Increment(ref writerTimeouts);
        }
    }

    // Shows how to request a reader lock, upgrade the
    // reader lock to the writer lock, and downgrade to a
    // reader lock again.
    static void UpgradeDowngrade(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);

                // If it is necessary to write to the resource,
                // you must either release the reader lock and 
                // then request the writer lock, or upgrade the
                // reader lock. Note that 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 is 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);
                }

                // When the lock has been downgraded, it is 
                // 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);
        }
    }

    // Shows how to release all locks and later restore
    // the lock state. Shows how to use sequence numbers
    // to determine whether another thread has obtained
    // a writer lock since this thread last accessed the
    // resource.
    static void ReleaseRestore(int timeOut)
    {
        int lastWriter;

        try
        {
            rwl.AcquireReaderLock(timeOut);
            try
            {
                // It is safe for this thread to read from
                // the shared resource. Cache the value. (You
                // might do this if reading the resource is
                // an expensive operation.)
                int resourceValue = resource;
                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 (up to a 
                // quarter of a second), and then restore
                // the previous state of the lock. Note that
                // there is no time-out on the Restore method.
                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. Comment out calls to Display to 
    // get a better idea of throughput.
    static void Display(string msg)
    {
        Console.Write("Thread {0} {1}.       \r", Thread.CurrentThread.Name, msg);
    }
}
Visual C++
// This example shows a ReaderWriterLock protecting a shared
// resource that is read concurrently and written exclusively
// by multiple threads.
// The complete code is located in the ReaderWriterLock
// class topic.
using namespace System;
using namespace System::Threading;
public ref class Test
{
public:

   // Declaring the ReaderWriterLock at the class level
   // makes it visible to all threads.
   static ReaderWriterLock^ rwl = gcnew ReaderWriterLock;

   // For this example, the shared resource protected by the
   // ReaderWriterLock is just an integer.
   static int resource = 0;

   literal int numThreads = 26;
   static bool running = true;
   static Random^ rnd = gcnew Random;

   // Statistics.
   static int readerTimeouts = 0;
   static int writerTimeouts = 0;
   static int reads = 0;
   static int writes = 0;
   static void ThreadProc()
   {

      // As long as a thread runs, it randomly selects
      // various ways to read and write from the shared 
      // resource. Each of the methods demonstrates one 
      // or more features of ReaderWriterLock.
      while ( running )
      {
         double action = rnd->NextDouble();
         if ( action < .8 )
                  ReadFromResource( 10 );
         else
         if ( action < .81 )
                  ReleaseRestore( 50 );
         else
         if ( action < .90 )
                  UpgradeDowngrade( 100 );
         else
                  WriteToResource( 100 );
      }
   }


   // Shows how to request and release a reader lock, and
   // how to 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( String::Format( "reads resource value {0}", resource ) );
            Interlocked::Increment( reads );
         }
         finally
         {

            // Ensure that the lock is released.
            rwl->ReleaseReaderLock();
         }

      }
      catch ( ApplicationException^ ) 
      {

         // The reader lock request timed out.
         Interlocked::Increment( readerTimeouts );
      }

   }


   // Shows how to request and release the writer lock, and
   // how to handle time-outs.
   static void WriteToResource( int timeOut )
   {
      try
      {
         rwl->AcquireWriterLock( timeOut );
         try
         {

            // It is safe for this thread to read or write
            // from the shared resource.
            resource = rnd->Next( 500 );
            Display( String::Format( "writes resource value {0}", resource ) );
            Interlocked::Increment( writes );
         }
         finally
         {

            // Ensure that the lock is released.
            rwl->ReleaseWriterLock();
         }

      }
      catch ( ApplicationException^ ) 
      {

         // The writer lock request timed out.
         Interlocked::Increment( writerTimeouts );
      }

   }


   // Shows how to request a reader lock, upgrade the
   // reader lock to the writer lock, and downgrade to a
   // reader lock again.
   static void UpgradeDowngrade( int timeOut )
   {
      try
      {
         rwl->AcquireReaderLock( timeOut );
         try
         {

            // It is safe for this thread to read from
            // the shared resource.
            Display( String::Format( "reads resource value {0}", resource ) );
            Interlocked::Increment( reads );

            // If it is necessary to write to the resource,
            // you must either release the reader lock and 
            // then request the writer lock, or upgrade the
            // reader lock. Note that 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 is safe for this thread to read or write
                  // from the shared resource.
                  resource = rnd->Next( 500 );
                  Display( String::Format( "writes resource value {0}", resource ) );
                  Interlocked::Increment( writes );
               }
               finally
               {

                  // Ensure that the lock is released.
                  rwl->DowngradeFromWriterLock( lc );
               }

            }
            catch ( ApplicationException^ ) 
            {

               // The upgrade request timed out.
               Interlocked::Increment( writerTimeouts );
            }


            // When the lock has been downgraded, it is 
            // still safe to read from the resource.
            Display( String::Format( "reads resource value {0}", resource ) );
            Interlocked::Increment( reads );
         }
         finally
         {

            // Ensure that the lock is released.
            rwl->ReleaseReaderLock();
         }

      }
      catch ( ApplicationException^ ) 
      {

         // The reader lock request timed out.
         Interlocked::Increment( readerTimeouts );
      }

   }


   // Shows how to release all locks and later restore
   // the lock state. Shows how to use sequence numbers
   // to determine whether another thread has obtained
   // a writer lock since this thread last accessed the
   // resource.
   static void ReleaseRestore( int timeOut )
   {
      int lastWriter;
      try
      {
         rwl->AcquireReaderLock( timeOut );
         try
         {

            // It is safe for this thread to read from
            // the shared resource. Cache the value. (You
            // might do this if reading the resource is
            // an expensive operation.)
            int resourceValue = resource;
            Display( String::Format( "reads resource value {0}", 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.
            LockCookie lc = rwl->ReleaseLock();

            // Wait for a random interval (up to a 
            // quarter of a second), and then restore
            // the previous state of the lock. Note that
            // there is no timeout on the Restore method.
            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 ) )
            {
               resourceValue = resource;
               Interlocked::Increment( reads );
               Display( String::Format( "resource has changed {0}", resourceValue ) );
            }
            else
            {
               Display( String::Format( "resource has not changed {0}", resourceValue ) );
            }
         }
         finally
         {

            // Ensure that the lock is released.
            rwl->ReleaseReaderLock();
         }

      }
      catch ( ApplicationException^ ) 
      {

         // The reader lock request timed out.
         Interlocked::Increment( readerTimeouts );
      }

   }


   // Helper method briefly displays the most recent
   // thread action. Comment out calls to Display to 
   // get a better idea of throughput.
   static void Display( String^ msg )
   {
      Console::Write( "Thread {0} {1}.       \r", Thread::CurrentThread->Name, msg );
   }

};


int main()
{
   array<String^>^args = Environment::GetCommandLineArgs();

   // Start a series of threads. Each thread randomly
   // performs reads and writes on the shared resource.
   array<Thread^>^t = gcnew array<Thread^>(Test::numThreads);
   for ( int i = 0; i < Test::numThreads; i++ )
   {
      t[ i ] = gcnew Thread( gcnew ThreadStart( Test::ThreadProc ) );
      t[ i ]->Name = gcnew String( Convert::ToChar( i + 65 ),1 );
      t[ i ]->Start();
      if ( i > 10 )
            Thread::Sleep( 300 );

   }

   // Tell the threads to shut down, then wait until they all
   // finish.
   Test::running = false;
   for ( int i = 0; i < Test::numThreads; i++ )
   {
      t[ i ]->Join();

   }

   // Display statistics.
   Console::WriteLine( "\r\n {0} reads, {1} writes, {2} reader time-outs, {3} writer time-outs.", Test::reads, Test::writes, Test::readerTimeouts, Test::writerTimeouts );
   Console::WriteLine( "Press ENTER to exit." );
   Console::ReadLine();
   return 0;
}

Inheritance Hierarchy

System..::.Object
  System.Runtime.ConstrainedExecution..::.CriticalFinalizerObject
    System.Threading..::.ReaderWriterLock
Thread Safety

This type is thread safe.

Platforms

Windows 7, Windows Vista, Windows XP SP2, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP Starter Edition, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, Windows Server 2000 SP4, Windows Millennium Edition, Windows 98

The .NET Framework and .NET Compact Framework do not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.
Version Information

.NET Framework

Supported in: 3.5, 3.0, 2.0, 1.1, 1.0
See Also

Reference

Other Resources

Tags :


Community Content

Thomas Lee
Don't use ReaderWriterLock

There are some serious issues with the ReaderWriterLock class, such that Microsoft implemented a replacement in .NET 3 called ReaderWriterLockSlim.

Jeffrey Richter, the Windows parallel programming guru, had this to say in a recent MSDN article: http://msdn2.microsoft.com/en-us/magazine/cc163599.aspx

"The Microsoft® .NET Framework Class Library includes a ReaderWriterLock class in the System.Threading namespace that lets you obtain multiple-reader/single-writer semantics. While it is nice that a class like this exists, there are several problems with its implementation and I recommend you do not use it."

He goes on to list some of the problems, including performance, policy, recursion, and resource leak problems.

Joe Duffy from the parallel programming team at Microsoft discusses the problem with this class in more detail, as well as the ReaderWriterLockSlim here: http://www.bluebytesoftware.com/blog/PermaLink,guid,54bf6c16-ce42-49d5-94db-aafbd7cb0c27.aspx

Instead of using this class, use the ReaderWriterLockSlim class in the .NET 3 framework. Or better yet, use one of Jeffrey Richter's high performance locks from his free PowerThreading library: http://wintellect.com/MemberOnly/PowerThreading.aspx


Page view tracker