Cet article a fait l'objet d'une traduction manuelle. Déplacez votre pointeur sur les phrases de l'article pour voir la version originale de ce texte. |
Traduction
Source
|
ReaderWriterLock, classe
Définit un verrou qui prend en charge les writers uniques et les lecteurs multiples.
System.Runtime.ConstrainedExecution.CriticalFinalizerObject
System.Threading.ReaderWriterLock
Assembly : mscorlib (dans mscorlib.dll)
Le type ReaderWriterLock expose les membres suivants.
| Nom | Description | |
|---|---|---|
|
ReaderWriterLock | Initialise une nouvelle instance de la classe ReaderWriterLock. |
| Nom | Description | |
|---|---|---|
|
IsReaderLockHeld | Obtient une valeur indiquant si le thread en cours détient un verrou de lecteur. |
|
IsWriterLockHeld | Obtient une valeur indiquant si le thread en cours détient le verrou de writer. |
|
WriterSeqNum | Obtient le numéro de séquence actuel. |
| Nom | Description | |
|---|---|---|
|
AcquireReaderLock(Int32) | Acquiert un verrou de lecteur en utilisant une valeur Int32 comme délai d'attente. |
|
AcquireReaderLock(TimeSpan) | Acquiert un verrou de lecteur en utilisant une valeur TimeSpan comme délai d'attente. |
|
AcquireWriterLock(Int32) | Acquiert un verrou de writer en utilisant une valeur Int32 comme délai d'attente. |
|
AcquireWriterLock(TimeSpan) | Acquiert un verrou de writer en utilisant une valeur TimeSpan comme délai d'attente. |
|
AnyWritersSince | Indique si le verrou de writer a été accordé à un thread depuis l'obtention du numéro de séquence. |
|
DowngradeFromWriterLock | Restaure le verrou du thread à l'état qu'il avait avant l'appel à UpgradeToWriterLock. |
|
Equals(Object) | Détermine si l'Object spécifié est égal à l'Object en cours. (Hérité de Object.) |
|
Finalize | Libère toutes les ressources utilisées par la classe CriticalFinalizerObject. (Hérité de CriticalFinalizerObject.) |
|
GetHashCode | Sert de fonction de hachage pour un type particulier. (Hérité de Object.) |
|
GetType | Obtient le Type de l'instance actuelle. (Hérité de Object.) |
|
MemberwiseClone | Crée une copie superficielle de l'objet Object actif. (Hérité de Object.) |
|
ReleaseLock | Libère le verrou quel que soit le nombre de fois où il a été acquis par le thread. |
|
ReleaseReaderLock | Décrémente le nombre de verrous. |
|
ReleaseWriterLock | Décrémente le nombre de verrous sur le verrou de writer. |
|
RestoreLock | Restaure l'état de verrou du thread au moment précédant l'appel à ReleaseLock. |
|
ToString | Retourne une chaîne qui représente l'objet actuel. (Hérité de Object.) |
|
UpgradeToWriterLock(Int32) | Met à niveau un verrou de lecteur vers le verrou de writer en utilisant une valeur Int32 pour définir le délai d'attente. |
|
UpgradeToWriterLock(TimeSpan) | Met à niveau un verrou de lecteur vers le verrou de writer en utilisant une valeur TimeSpan pour définir le délai d'attente. |
Important
|
|---|
|
Le .NET Framework a deux verrous de writer de lecteur, ReaderWriterLockSlimet ReaderWriterLock. ReaderWriterLockSlim est recommandé pout tout nouveau développement. ReaderWriterLockSlim est semblable à ReaderWriterLock, mais les règles de récurrence et de mise à niveau et rétrogradation de l'état de verrou sont simplifiées. ReaderWriterLockSlim évite de nombreux cas d'interblocage potentiel. De plus, la performance de ReaderWriterLockSlim est considérablement meilleure que ReaderWriterLock. |
ReaderWriterLock sert à synchroniser l'accès à une ressource. Il permet à tout moment un accès en lecture simultané à plusieurs threads ou un accès en écriture à un seul thread. Dans le cas d'une ressource rarement modifiée, un ReaderWriterLock offre un meilleur débit que le simple verrou permettant un seul accès à la fois, comme Monitor.
ReaderWriterLock est le plus efficace dans le cas où la plupart des accès sont des accès en lecture et où les accès en écriture sont rares et de courte durée. Les lecteurs multiples alternent avec les writers uniques de sorte qui ni les lecteurs ni les writers ne sont bloqués pendant de longues périodes.
Remarque
|
|---|
|
Le maintien de verrous de lecteur ou de writer pendant de longues périodes retarde l'exécution d'autres threads. Pour optimiser les performances, envisagez de restructurer votre application afin de limiter la durée des accès en écriture. |
Un thread peut détenir un verrou de lecteur ou un verrou de writer mais pas les deux en même temps. Au lieu de libérer un verrou de lecteur pour acquérir le verrou de writer, vous pouvez utiliser UpgradeToWriterLock et DowngradeFromWriterLock.
Des demandes de verrou récursives font augmenter le nombre de verrous sur un verrou.
Les lecteurs et les writers sont placés dans des files d'attente séparées. Lorsqu'un thread libère le verrou de writer, des verrous de lecteur sont octroyés à tous les threads en attente dans la file de lecteurs ; lorsque tous ces verrous de lecteur ont été libérés, le verrou de writer est octroyé au thread suivant de la file d'attente de writers, s'il y en a un, et ainsi de suite. En d'autres termes, ReaderWriterLock alterne entre une collection de lecteurs et un seul writer.
Pendant qu'un thread de la file d'attente des writers attend que des verrous de lecteur actifs soient libérés, les threads demandant de nouveaux verrous de lecteur s'accumulent dans la file d'attente des lecteurs. Leurs demandes ne sont pas acceptées même s'ils peuvent partager un accès simultané avec des détenteurs de verrous de lecteur existants ; de cette façon les writers sont mieux protégés contre un verrouillage indéfini par les lecteurs.
La plupart des méthodes d'acquisition de verrous sur un ReaderWriterLock acceptent des valeurs d'expiration. Utilisez les valeurs d'expiration pour éviter les interblocages dans votre application. Par exemple, un thread peut acquérir le verrou de writer sur une ressource puis demander un verrou de lecteur sur une seconde ressource ; dans l'intervalle, un autre thread peut acquérir le verrou de writer sur la seconde ressource et demander un verrou de lecteur sur la première. À moins de définir des valeurs d'expiration, les threads se bloquent mutuellement.
Si le délai d'attente expire et que la demande de verrou n'a pas été accordée, la méthode retourne le contrôle au thread appelant en levant une ApplicationException. Un thread peut intercepter cette exception et décider de la prochaine action à effectuer.
Les délais d'attente sont exprimés en millisecondes. Si vous utilisez un System.TimeSpan pour spécifier le délai d'attente, la valeur utilisée est le total des millisecondes entières représentées par TimeSpan. Le tableau suivant indique les valeurs de délai d'attente valides en millisecondes.
|
Valeur |
Description |
|---|---|
|
-1 |
Le thread attend jusqu'à ce que le verrou soit acquis, quelle que soit la durée nécessaire. Pour les méthodes qui spécifient des délais d'expiration entiers, la constante Infinite peut être utilisée. |
|
0 |
Le thread n'attend pas pour acquérir le verrou. Si le verrou ne peut pas être acquis immédiatement, la méthode retourne. |
|
>0 |
Nombre de millisecondes à attendre. |
À l'exception de -1, les délais d'attente négatifs ne sont pas admis. Si vous spécifiez un entier négatif autre que -1, un délai d'attente égal à zéro est utilisé. (Autrement dit, la méthode retourne sans attendre si le verrou ne peut pas être acquis immédiatement.) Si vous spécifiez un TimeSpan qui représente un nombre négatif de millisecondes autre que -1, le système lève une ArgumentOutOfRangeException.
Remarque
|
|---|
|
L'attribut HostProtectionAttribute appliqué à ce type ou membre a la valeur de propriété Resources suivante : Synchronization | ExternalThreading. HostProtectionAttribute n'affecte pas les applications bureautiques (qui sont généralement démarrées en double-cliquant sur une icône, en tapant une commande ou en entrant une URL dans un navigateur). Pour plus d'informations, consultez la classe HostProtectionAttribute ou Attributs de programmation et de protection des hôtes SQL Server. |
L'exemple suivant montre comment utiliser un ReaderWriterLock pour protéger une ressource partagée qui est lue simultanément et est écrite exclusivement par plusieurs 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. 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); } }
Windows 7, Windows Vista SP1 ou ultérieur, Windows XP SP3, Windows XP SP2 Édition x64, Windows Server 2008 (installation minimale non prise en charge), Windows Server 2008 R2 (installation minimale prise en charge avec SP1 ou version ultérieure), Windows Server 2003 SP2
Le .NET Framework ne prend pas en charge toutes les versions de chaque plateforme. Pour obtenir la liste des versions prises en charge, consultez Configuration requise du .NET Framework.
Important
Remarque