.NET Framework Class Library ReaderWriterLock Class Defines a lock that supports single writers and multiple readers.

Inheritance Hierarchy
Namespace:
System.Threading
Assembly:
mscorlib (in mscorlib.dll)

Syntax
<ComVisibleAttribute(True)> _
<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization := True, _
ExternalThreading := True)> _
Public NotInheritable Class ReaderWriterLock _
Inherits CriticalFinalizerObject
[ComVisibleAttribute(true)]
[HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true,
ExternalThreading = true)]
public sealed class ReaderWriterLock : CriticalFinalizerObject
[ComVisibleAttribute(true)]
[HostProtectionAttribute(SecurityAction::LinkDemand, Synchronization = true,
ExternalThreading = true)]
public ref class ReaderWriterLock sealed : public CriticalFinalizerObject
[<Sealed>]
[<ComVisibleAttribute(true)>]
[<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true,
ExternalThreading = true)>]
type ReaderWriterLock =
class
inherit CriticalFinalizerObject
end
The ReaderWriterLock type exposes the following members.

Constructors

Methods

Remarks
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. Note |
|---|
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.
' 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
// 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);
}
}
// 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;
}

Version Information
.NET FrameworkSupported in: 4, 3.5, 3.0, 2.0, 1.1, 1.0 .NET Framework Client ProfileSupported in: 4, 3.5 SP1

Platforms
Windows 7, Windows Vista SP1 or later, Windows XP SP3, Windows XP SP2 x64 Edition, Windows Server 2008 (Server Core Role not supported), Windows Server 2008 R2 (Server Core Role not supported), Windows Server 2003 SP2
The .NET Framework does not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.

Thread Safety
This type is thread safe.

See Also
|
Biblioteca de clases de .NET Framework ReaderWriterLock (Clase) Define un bloqueo que admite un escritor y varios lectores.

Jerarquía de herencia
Espacio de nombres:
System.Threading
Ensamblado:
mscorlib (en mscorlib.dll)

Sintaxis
<ComVisibleAttribute(True)> _
<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization := True, _
ExternalThreading := True)> _
Public NotInheritable Class ReaderWriterLock _
Inherits CriticalFinalizerObject
[ComVisibleAttribute(true)]
[HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true,
ExternalThreading = true)]
public sealed class ReaderWriterLock : CriticalFinalizerObject
[ComVisibleAttribute(true)]
[HostProtectionAttribute(SecurityAction::LinkDemand, Synchronization = true,
ExternalThreading = true)]
public ref class ReaderWriterLock sealed : public CriticalFinalizerObject
[<Sealed>]
[<ComVisibleAttribute(true)>]
[<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true,
ExternalThreading = true)>]
type ReaderWriterLock =
class
inherit CriticalFinalizerObject
end
El tipo ReaderWriterLock expone los siguientes miembros.

Constructores

Métodos

Comentarios
Importante |
|---|
.NET Framework dispone de dos bloqueos de lector y escritor, ReaderWriterLockSlim y ReaderWriterLock. ReaderWriterLockSlim se recomienda para todos los trabajos de desarrollo nuevos. ReaderWriterLockSlim es similar a ReaderWriterLock, pero tiene reglas simplificadas para la recursividad y para actualizar y degradar el estado del bloqueo. ReaderWriterLockSlim evita muchos casos de interbloqueo potencial. Además, el rendimiento de ReaderWriterLockSlim es significativamente mejor que ReaderWriterLock. |
ReaderWriterLock se utiliza para sincronizar el acceso a un recurso. En cualquier momento dado, permite el acceso de lectura simultáneo de varios subprocesos o el acceso de escritura de un solo subproceso. En una situación en la que un recurso se cambia raramente, ReaderWriterLock proporciona mejor rendimiento que un simple bloqueo de uno en uno, como Monitor.
ReaderWriterLock funciona mejor si la mayoría de los accesos son de lectura y las escrituras son pocas y de corta duración. Se alternan varios lectores con escritores únicos, para que ni lectores ni escritores queden bloqueados largos períodos de tiempo. Nota |
|---|
Si se mantienen bloqueos de lectores o de escritores durante largos períodos de tiempo, otros subprocesos quedarán sin recursos. Para obtener un mejor rendimiento, se puede reestructurar la aplicación de manera que se minimice la duración de las escrituras. |
Un subproceso puede contener un bloqueo de lector o de escritor, pero no los dos a la vez. En lugar de liberar un bloqueo de lector para adquirir el bloqueo de escritor, se puede utilizar UpgradeToWriterLock y DowngradeFromWriterLock. Las solicitudes de bloqueo recursivas aumentan el recuento de bloqueos de un bloqueo. Los lectores y los escritores forman colas independientes. Cuando un subproceso libera el bloqueo del escritor, todos los subprocesos en espera de la cola del lector reciben en ese momento bloqueos de lector; cuando se liberan todos esos bloqueos de lector, el siguiente subproceso en espera de la cola del escritor, si lo hay, recibe un bloqueo de escritor, y así sucesivamente. En otras palabras, ReaderWriterLock alterna entre una colección de lectores y un escritor. Si hay un subproceso en la cola del escritor esperando a que se liberen bloqueos activos de lector, los subprocesos que solicitan nuevos bloqueos de lector se acumulan en la cola del lector. Estas solicitudes no se conceden, aunque podrían compartir el acceso simultáneo con propietarios de bloqueos de lector existentes; de esta forma se ayuda a proteger a los escritores frente a bloqueos indefinidos por parte de los lectores. La mayoría de los métodos para adquirir bloqueos en un ReaderWriterLock aceptan valores de tiempo de espera. Utilice tiempos de espera para evitar interbloqueos en la aplicación. Por ejemplo, un subproceso puede adquirir el bloqueo de escritor en un recurso y, a continuación, solicitar un bloqueo de lector en otro; mientras tanto, otro subproceso podría adquirir el bloqueo de escritor del segundo recurso y solicitar un bloqueo de lector en el primero. A menos que se utilicen tiempos de espera, los subprocesos se interbloquean. Si expira el tiempo de espera y la solicitud de bloqueo no se ha concedido, el método devuelve el control al subproceso que realiza la llamada produciendo ApplicationException. Un subproceso puede detectar esta excepción y decidir qué se debe hacer a continuación. Los tiempos de espera se expresan en milisegundos. Si se utiliza System..::.TimeSpan para especificar el tiempo de espera, el valor utilizado es el número total de milisegundos que representa TimeSpan. En la tabla siguiente se muestran los valores de tiempo de espera válidos, en milisegundos. Valor | Descripción |
|---|
-1 | El subproceso espera hasta que se adquiere el bloqueo, sin tener en cuenta el tiempo que tarda. Para los métodos que especifican tiempos de espera enteros, se puede usar la constante Infinite. | 0 | El subproceso no espera para adquirir el bloqueo. Si no se puede adquirir el bloqueo inmediatamente, el método regresa. | >0 | Número de milisegundos durante los que se va a esperar. |
A excepción de -1, no se permiten valores de tiempo de espera negativos. Si se especifica un entero negativo distinto de -1, se usa un valor de tiempo de espera cero (es decir, el método regresa sin esperar si no se puede adquirir el bloqueo inmediatamente). Si se especifica un TimeSpan que representa un número negativo de milisegundos que no sea -1, se produce ArgumentOutOfRangeException.

Ejemplos
El ejemplo siguiente muestra cómo utilizar ReaderWriterLock para proteger un recurso compartido que varios subprocesos leen de forma concurrente y escriben de forma exclusiva.
' 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
// 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);
}
}
// 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;
}

Información de versión
.NET FrameworkCompatible con: 4, 3.5, 3.0, 2.0, 1.1, 1.0 .NET Framework Client ProfileCompatible con: 4, 3.5 SP1

Plataformas
Windows 7, Windows Vista SP1 o posterior, Windows XP SP3, Windows XP SP2 x64 Edition, Windows Server 2008 (no se admite Server Core), Windows Server 2008 R2 (se admite Server Core con SP1 o posterior), Windows Server 2003 SP2
.NET Framework no admite todas las versiones de todas las plataformas. Para obtener una lista de las versiones compatibles, vea Requisitos de sistema de .NET Framework.

Seguridad para subprocesos
Este tipo es seguro para la ejecución de subprocesos.

Vea también
|