ReaderWriterLock Klas
Definitie
Belangrijk
Bepaalde informatie heeft betrekking op een voorlopige productversie die aanzienlijk kan worden gewijzigd voordat deze wordt uitgebracht. Microsoft biedt geen enkele expliciete of impliciete garanties met betrekking tot de informatie die hier wordt verstrekt.
Definieert een vergrendeling die ondersteuning biedt voor individuele schrijvers en meerdere lezers.
public ref class ReaderWriterLock sealed
public ref class ReaderWriterLock sealed : System::Runtime::ConstrainedExecution::CriticalFinalizerObject
public sealed class ReaderWriterLock
[System.Runtime.InteropServices.ComVisible(true)]
public sealed class ReaderWriterLock : System.Runtime.ConstrainedExecution.CriticalFinalizerObject
public sealed class ReaderWriterLock : System.Runtime.ConstrainedExecution.CriticalFinalizerObject
type ReaderWriterLock = class
[<System.Runtime.InteropServices.ComVisible(true)>]
type ReaderWriterLock = class
inherit CriticalFinalizerObject
type ReaderWriterLock = class
inherit CriticalFinalizerObject
Public NotInheritable Class ReaderWriterLock
Public NotInheritable Class ReaderWriterLock
Inherits CriticalFinalizerObject
- Overname
-
ReaderWriterLock
- Overname
- Kenmerken
Voorbeelden
In het volgende voorbeeld ziet u hoe u een ReaderWriterLock gedeelde resource, een geheel getal met de naam resource, dat gelijktijdig wordt gelezen en exclusief door meerdere threads wordt geschreven. Houd er rekening mee dat het ReaderWriterLock is gedeclareerd op klasseniveau, zodat deze zichtbaar is voor alle threads.
// 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
Opmerkingen
Important
.NET Framework heeft twee vergrendelingen voor lezersschrijvers, ReaderWriterLockSlim en ReaderWriterLock. ReaderWriterLockSlim wordt aanbevolen voor alle nieuwe ontwikkelingen. ReaderWriterLockSlim is vergelijkbaar met ReaderWriterLock, maar het heeft vereenvoudigde regels voor recursie en voor het upgraden en downgraden van de vergrendelingsstatus. ReaderWriterLockSlim vermijdt veel gevallen van mogelijke impasse. Daarnaast is de prestaties ReaderWriterLockSlim aanzienlijk beter dan ReaderWriterLock.
ReaderWriterLock wordt gebruikt om de toegang tot een resource te synchroniseren. Op elk gewenst moment is gelijktijdige leestoegang mogelijk voor meerdere threads of schrijftoegang voor één thread. In een situatie waarin een resource zelden wordt gewijzigd, biedt een ReaderWriterLock betere doorvoer dan een eenvoudige eenmalige vergrendeling, zoals Monitor.
ReaderWriterLock werkt het beste wanneer de meeste toegang leesbewerkingen zijn, terwijl schrijfbewerkingen niet vaak en van korte duur zijn. Meerdere lezers wisselen af met één schrijvers, zodat lezers en schrijvers gedurende lange perioden niet worden geblokkeerd.
Note
Het vasthouden van vergrendelingen of schrijfvergrendelingen voor lange perioden zal andere threads verhongeren. Voor de beste prestaties kunt u overwegen uw toepassing te herstructureren om de duur van schrijfbewerkingen te minimaliseren.
Een thread kan een lezervergrendeling of een schrijfvergrendeling bevatten, maar niet beide tegelijk. In plaats van een lezervergrendeling vrij te geven om de schrijfvergrendeling te verkrijgen, kunt u deze gebruiken UpgradeToWriterLock en DowngradeFromWriterLock.
Recursieve vergrendelingsaanvragen verhogen het aantal vergrendelingen op een vergrendeling.
Lezers en schrijvers worden afzonderlijk in de wachtrij geplaatst. Wanneer een thread de schrijververgrendeling loslaat, krijgen alle threads die in de wachtrij van de lezer op dat moment wachten, lezersvergrendelingen verleend; wanneer al deze lezervergrendelingen zijn vrijgegeven, wordt de volgende thread die in de wachtrij voor schrijver wacht, indien aanwezig, de schrijververgrendeling verleend, enzovoort. Met andere woorden, ReaderWriterLock wisselt tussen een verzameling lezers en één schrijver.
Terwijl een thread in de schrijfwachtrij wacht tot actieve lezervergrendelingen worden vrijgegeven, worden threads die nieuwe lezervergrendelingen aanvragen, verzameld in de wachtrij voor lezers. Hun verzoeken worden niet verleend, ook al kunnen ze gelijktijdige toegang delen met bestaande lezervergrendelingshouders; dit helpt schrijvers te beschermen tegen onbepaalde blokkering door lezers.
De meeste methoden voor het verkrijgen van vergrendelingen voor een ReaderWriterLock time-out voor accepteren. Gebruik time-outs om impasses in uw toepassing te voorkomen. Een thread kan bijvoorbeeld de schrijfvergrendeling op één resource verkrijgen en vervolgens een lezervergrendeling aanvragen voor een tweede resource; ondertussen kan een andere thread de schrijfvergrendeling op de tweede resource verkrijgen en een lezervergrendeling aanvragen bij de eerste. Tenzij time-outs worden gebruikt, zijn de threads impasse.
Als het time-outinterval verloopt en de vergrendelingsaanvraag niet is verleend, retourneert de methode het besturingselement naar de aanroepende thread door een ApplicationException. Een thread kan deze uitzondering ondervangen en bepalen welke actie moet worden ondernomen.
Time-outs worden uitgedrukt in milliseconden. Als u een System.TimeSpan time-out gebruikt om de time-out op te geven, is de gebruikte waarde het totale aantal gehele milliseconden dat wordt vertegenwoordigd door de TimeSpan. In de volgende tabel ziet u de geldige time-outwaarden in milliseconden.
| Value | Description |
|---|---|
| -1 | De thread wacht totdat de vergrendeling is verkregen, ongeacht hoe lang het duurt. Voor methoden die time-outs voor gehele getallen opgeven, kan de constante Infinite worden gebruikt. |
| 0 | De thread wacht niet om de vergrendeling te verkrijgen. Als de vergrendeling niet onmiddellijk kan worden verkregen, retourneert de methode. |
| >0 | Het aantal milliseconden dat moet worden gewacht. |
Met uitzondering van -1 zijn negatieve time-outwaarden niet toegestaan. Als u een ander negatief geheel getal dan -1 opgeeft, wordt in plaats daarvan een time-outwaarde van nul gebruikt. (Dat wil gezegd, de methode retourneert zonder te wachten, als de vergrendeling niet onmiddellijk kan worden verkregen.) Als u een TimeSpan getal opgeeft dat een negatief aantal milliseconden vertegenwoordigt dan -1, ArgumentOutOfRangeException wordt er een gegenereerd.
Constructors
| Name | Description |
|---|---|
| ReaderWriterLock() |
Initialiseert een nieuw exemplaar van de ReaderWriterLock klasse. |
Eigenschappen
| Name | Description |
|---|---|
| IsReaderLockHeld |
Hiermee wordt een waarde opgehaald die aangeeft of de huidige thread een lezervergrendeling bevat. |
| IsWriterLockHeld |
Hiermee wordt een waarde opgehaald die aangeeft of de huidige thread de schrijfvergrendeling bevat. |
| WriterSeqNum |
Hiermee haalt u het huidige volgnummer op. |
Methoden
| Name | Description |
|---|---|
| AcquireReaderLock(Int32) |
Hiermee verkrijgt u een lezervergrendeling met behulp van een Int32 waarde voor de time-out. |
| AcquireReaderLock(TimeSpan) |
Hiermee verkrijgt u een lezervergrendeling met behulp van een TimeSpan waarde voor de time-out. |
| AcquireWriterLock(Int32) |
Hiermee verkrijgt u de schrijververgrendeling met behulp van een Int32 waarde voor de time-out. |
| AcquireWriterLock(TimeSpan) |
Hiermee verkrijgt u de schrijververgrendeling met behulp van een TimeSpan waarde voor de time-out. |
| AnyWritersSince(Int32) |
Geeft aan of de schrijververgrendeling is verleend aan een thread sinds het volgnummer is verkregen. |
| DowngradeFromWriterLock(LockCookie) |
Hiermee herstelt u de vergrendelingsstatus van de thread naar wat het eerder UpgradeToWriterLock(Int32) was aangeroepen. |
| Equals(Object) |
Bepaalt of het opgegeven object gelijk is aan het huidige object. (Overgenomen van Object) |
| Finalize() |
Zorgt ervoor dat resources worden vrijgemaakt en andere opschoonbewerkingen worden uitgevoerd wanneer de garbagecollector het ReaderWriterLock object terugvordert. |
| GetHashCode() |
Fungeert als de standaardhashfunctie. (Overgenomen van Object) |
| GetType() |
Hiermee haalt u de Type huidige instantie op. (Overgenomen van Object) |
| MemberwiseClone() |
Hiermee maakt u een ondiepe kopie van de huidige Object. (Overgenomen van Object) |
| ReleaseLock() |
Hiermee wordt de vergrendeling vrijgegeven, ongeacht het aantal keren dat de thread de vergrendeling heeft verkregen. |
| ReleaseReaderLock() |
Hiermee wordt het aantal vergrendelingen afgerekend. |
| ReleaseWriterLock() |
Hiermee wordt het aantal vergrendelingen op het schrijfslot afschroeven. |
| RestoreLock(LockCookie) |
Hiermee herstelt u de vergrendelingsstatus van de thread naar wat deze was voordat u aanroept ReleaseLock(). |
| ToString() |
Retourneert een tekenreeks die het huidige object vertegenwoordigt. (Overgenomen van Object) |
| UpgradeToWriterLock(Int32) |
Hiermee wordt een lezervergrendeling bijgewerkt naar de schrijververgrendeling, met behulp van een Int32 waarde voor de time-out. |
| UpgradeToWriterLock(TimeSpan) |
Hiermee wordt een lezervergrendeling bijgewerkt naar de schrijververgrendeling, met behulp van een |
Van toepassing op
Veiligheid thread
Dit type is thread veilig.
Zie ook
- Het Beheerd Draadbeheer
- ReaderWriterLock