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
Ce sujet n'a pas encore été évalué - Évaluez ce sujet

ReaderWriterLockSlim, classe

Représente un verrou utilisé pour gérer l'accès à une ressource, en autorisant plusieurs threads pour la lecture ou un accès exclusif en écriture.

System.Object
  System.Threading.ReaderWriterLockSlim

Espace de noms :  System.Threading
Assembly :  System.Core (dans System.Core.dll)
[HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
[HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, 
	ExternalThreading = true)]
public class ReaderWriterLockSlim : IDisposable

Le type ReaderWriterLockSlim expose les membres suivants.

  Nom Description
Méthode publique ReaderWriterLockSlim() Initialise une nouvelle instance de la classe ReaderWriterLockSlim avec des valeurs de propriété par défaut.
Méthode publique ReaderWriterLockSlim(LockRecursionPolicy) Initialise une nouvelle instance de la classe ReaderWriterLockSlim, en spécifiant la stratégie de récurrence du verrou.
Début
  Nom Description
Propriété publique CurrentReadCount Obtient le nombre total de threads uniques qui ont entré le verrou en mode lecture.
Propriété publique IsReadLockHeld Obtient une valeur qui indique si le thread actuel a entré le verrou en mode lecture.
Propriété publique IsUpgradeableReadLockHeld Obtient une valeur qui indique si le thread actuel a entré le verrou en mode de mise à niveau.
Propriété publique IsWriteLockHeld Obtient une valeur qui indique si le thread actuel a entré le verrou en mode écriture.
Propriété publique RecursionPolicy Obtient une valeur qui indique la stratégie de récurrence pour l'objet ReaderWriterLockSlim actuel.
Propriété publique RecursiveReadCount Obtient le nombre de fois où le thread actuel a entré le verrou en mode lecture, comme une indication de récurrence.
Propriété publique RecursiveUpgradeCount Obtient le nombre de fois où le thread actuel a entré le verrou en mode de mise à niveau, comme une indication de récurrence.
Propriété publique RecursiveWriteCount Obtient le nombre de fois où le thread actuel a entré le verrou en mode écriture, comme une indication de récurrence.
Propriété publique WaitingReadCount Obtient le nombre total de threads qui attendent pour entrer le verrou en mode lecture.
Propriété publique WaitingUpgradeCount Obtient le nombre total de threads qui attendent pour entrer le verrou en mode de mise à niveau.
Propriété publique WaitingWriteCount Obtient le nombre total de threads qui attendent pour entrer le verrou en mode écriture.
Début
  Nom Description
Méthode publique Dispose Libère toutes les ressources utilisées par l'instance actuelle de la classe ReaderWriterLockSlim.
Méthode publique EnterReadLock Essaie d'entrer le verrou en mode lecture.
Méthode publique EnterUpgradeableReadLock Essaie d'entrer le verrou en mode de mise à niveau.
Méthode publique EnterWriteLock Essaie d'entrer le verrou en mode écriture.
Méthode publique Equals(Object) Détermine si l'Object spécifié est égal à l'Object en cours. (Hérité de Object.)
Méthode publique ExitReadLock Réduit le nombre de récurrences pour le mode lecture, et quitte le mode lecture si le compte résultant est 0 (zéro).
Méthode publique ExitUpgradeableReadLock Réduit le nombre de récurrences pour le mode de mise à niveau, et quitte le mode de mise à niveau si le compte résultant est 0 (zéro).
Méthode publique ExitWriteLock Réduit le nombre de récurrences pour le mode écriture, et quitte le mode écriture si le compte résultant est 0 (zéro).
Méthode protégée Finalize Autorise un objet à tenter de libérer des ressources et d'exécuter d'autres opérations de netto***ge avant qu'il ne soit récupéré par l'opération garbage collection. (Hérité de Object.)
Méthode publique GetHashCode Sert de fonction de hachage pour un type particulier. (Hérité de Object.)
Méthode publique GetType Obtient le Type de l'instance actuelle. (Hérité de Object.)
Méthode protégée MemberwiseClone Crée une copie superficielle de l'objet Object actif. (Hérité de Object.)
Méthode publique ToString Retourne une chaîne qui représente l'objet actuel. (Hérité de Object.)
Méthode publique TryEnterReadLock(Int32) Essaie d'entrer le verrou en mode lecture, avec un délai d'attente entier facultatif.
Méthode publique TryEnterReadLock(TimeSpan) Essaie d'entrer le verrou en mode lecture, avec un délai d'attente facultatif.
Méthode publique TryEnterUpgradeableReadLock(Int32) Essaie d'entrer le verrou en mode de mise à niveau, avec un délai d'attente facultatif.
Méthode publique TryEnterUpgradeableReadLock(TimeSpan) Essaie d'entrer le verrou en mode de mise à niveau, avec un délai d'attente facultatif.
Méthode publique TryEnterWriteLock(Int32) Essaie d'entrer le verrou en mode écriture, avec un délai d'attente facultatif.
Méthode publique TryEnterWriteLock(TimeSpan) Essaie d'entrer le verrou en mode écriture, avec un délai d'attente facultatif.
Début

Utilisez ReaderWriterLockSlim pour protéger une ressource lue par plusieurs threads et écrite par un thread à la fois. ReaderWriterLockSlim permet à plusieurs threads d'être en mode lecture, à un thread d'être en mode écriture avec la propriété exclusive du verrou et à un thread ayant un accès en lecture d'être en mode lecture avec mise à niveau, mode à partir duquel le thread peut effectuer une mise à niveau en mode écriture sans devoir annuler son accès en lecture à la ressource.

Remarque Remarque

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. ReaderWriterLockSlim est recommandé pout tout nouveau développement.

Par défaut, les nouvelles instances de ReaderWriterLockSlim sont créées avec l'indicateur LockRecursionPolicy.NoRecursion et n'autorisent pas la récurrence. Cette stratégie par défaut est recommandée pour tout développement nouveau, parce que la récurrence introduit des complications inutiles et augmente le risque d'interblocage de votre code. Pour simplifier la migration de projets existants qui utilisent Monitor ou ReaderWriterLock, vous pouvez utiliser l'indicateur LockRecursionPolicy.SupportsRecursion pour créer des instances de ReaderWriterLockSlim autorisant la récurrence.

Un thread peut entrer le verrou en trois modes : mode lecture, mode écriture et mode de lecture avec mise à niveau. (Dans le reste de cette rubrique, le « mode lecture avec mise à niveau » est appelé « mode de mise à niveau » et l'expression « entrer en mode x» est utilisée à la place de l'expression complète « entrer le verrou en mode x.)

Indépendamment de la stratégie de récurrence, un seul thread peut se trouver en mode écriture à un moment donné. Lorsqu'un thread est en mode écriture, aucun autre thread ne peut entrer le verrou dans un mode quelconque. Un seul thread peut être en mode de mise à niveau à un moment donné. Un nombre quelconque de threads peut être en mode lecture, et il peut y avoir un thread en mode de mise à niveau alors que les autres threads sont en mode lecture.

ReaderWriterLockSlim présente une affinité de thread managée ; en d'autres termes, chaque objet Thread doit émettre ses propres appels de méthode pour entrer et sortir des modes de verrouillage. Aucun thread ne peut modifier le mode d'un autre thread.

Si un ReaderWriterLockSlim n'autorise pas la récurrence, un thread qui essaie d'entrer le verrou peut bloquer pour plusieurs raisons :

  • Un thread qui essaie d'entrer en mode lecture bloque si des threads attendent pour entrer en mode écriture ou s'il y a un thread unique en mode écriture.

    Remarque Remarque

    Bloquer les nouveaux lecteurs alors que des writers sont en file d'attente est une stratégie d'équité du verrou qui favorise les writers. La stratégie d'équité actuelle établit un équilibre entre lecteurs et writers, afin de favoriser le débit dans les scénarios les plus courants. Les versions futures du .NET Framework peuvent introduire de nouvelles stratégies d'équité.

  • Un thread qui essaie d'entrer en mode de mise à niveau bloque si un autre thread est déjà en mode de mise à niveau, si des threads attendent pour entrer en mode écriture, ou s'il y a un thread unique en mode écriture.

  • Un thread qui essaie d'entrer en mode écriture bloque si un autre thread est déjà dans l'un de ces trois modes.

Mise à niveau et rétrogradation des verrous

Le mode de mise à niveau est prévu pour les cas où un thread lit habituellement une ressource protégée, mais peut être amené à écrire sur cette ressource en présence de certaines conditions. Un thread qui a entré un ReaderWriterLockSlim en mode de mise à niveau a un accès en lecture à la ressource protégée et peut mettre à niveau vers le mode écriture en appelant EnterWriteLock ou les méthodes TryEnterWriteLock. Comme seul un thread peut se trouver en mode de mise à niveau à un moment donné, la mise à niveau vers le mode écriture ne peut pas bloquer lorsque la récurrence n'est pas autorisée, ce qui est la stratégie par défaut.

Remarque importante Important

Indépendamment de la stratégie de récurrence, un thread qui est entré à l'origine en mode lecture n'est pas autorisé à mettre à niveau vers un mode pouvant être mis à niveau ou un mode écriture, parce que ce modèle crée une forte probabilité d'interblocage. Par exemple, si deux threads en mode lecture essaient tous deux d'entrer en mode écriture, ils se bloqueront. Le mode de mise à niveau est conçu pour éviter de tels interblocages.

Si d'autres threads sont en mode lecture, le thread qui met à niveau bloque. Pendant que le thread est bloqué, les autres threads qui essaient d'entrer en mode lecture sont bloqués. Lorsque tous les threads ont quitté le mode lecture, le thread de mise à niveau bloqué entre en mode écriture. Si d'autres threads attendent pour entrer en mode écriture, ils restent bloqués, parce que le seul thread qui est en mode de mise à niveau les empêche d'obtenir l'accès exclusif à la ressource.

Lorsque le thread en mode de mise à niveau quitte le mode écriture, les autres threads qui attendent pour entrer en mode lecture peuvent alors le faire, sauf si des threads attendent pour entrer en mode écriture. Le thread en mode de mise à niveau peut mettre à niveau et rétrograder indéfiniment, tant que c'est le seul thread qui écrit dans la ressource protégée.

Remarque importante Important

Si vous permettez à plusieurs threads d'entrer en mode écriture ou en mode de mise à niveau, vous ne devez pas autoriser un thread à monopoliser le mode de mise à niveau. Sinon, les threads qui essaient d'entrer directement en mode écriture seront bloqués indéfiniment, et tant qu'ils sont bloqués, les autres threads ne pourront pas entrer en mode lecture.

Un thread en mode de mise à niveau peut rétrograder en mode lecture en appelant d'abord la méthode EnterReadLock , puis la méthode ExitUpgradeableReadLock. Ce modèle de rétrogradation est autorisé pour toutes les stratégies de récurrence de verrou, y compris NoRecursion.

Après avoir rétrogradé en mode lecture, un thread ne peut pas réentrer en mode de mise à niveau tant qu'il n'a pas quitté le mode lecture.

Entrée récursive du verrou

Vous pouvez créer un ReaderWriterLockSlim qui prend en charge l'entrée récursive de verrou en utilisant le constructeur ReaderWriterLockSlim(LockRecursionPolicy) qui spécifie la stratégie de verrou, et en spécifiant LockRecursionPolicy.SupportsRecursion.

Remarque Remarque

L'utilisation de la stratégie de récurrence n'est pas recommandée pour les développements nouveaux, parce que la récurrence introduit des complications inutiles et augmente le risque d'interblocage de votre code.

Pour un ReaderWriterLockSlim qui autorise la récurrence, voici les informations sur les modes qu'un thread peut utiliser :

  • Un thread en mode lecture peut entrer en mode lecture de manière récursive, mais ne peut pas entrer en mode écriture ou en mode de mise à niveau. S'il tente de le faire, une exception LockRecursionException est levée. L'entrée en mode lecture puis en mode écriture ou en mode de mise à niveau est un scénario avec une probabilité forte d'interblocages, donc il n'est pas autorisé. Comme indiqué précédemment, le mode de mise à niveau est prévu pour les cas où il est nécessaire de mettre à niveau un verrou.

  • Un thread en mode de mise à niveau peut entrer en mode écriture et/ou en mode lecture et peut entrer dans chacun de ces trois modes de manière récursive. Toutefois, une tentative d'entrer en mode écriture bloque si d'autres threads sont en mode lecture.

  • Un thread en mode écriture peut entrer en mode lecture et/ou en mode de mise à niveau et peut entrer dans chacun de ces trois modes de manière récursive.

  • Un thread qui n'a pas entré de verrou peut entrer dans n'importe quel mode. Cette tentative peut bloquer pour les mêmes raisons qu'une tentative d'entrer un verrou non récursif.

Un thread peut quitter les modes dans lesquels il est entré dans n'importe quel ordre, à condition de quitter chaque mode exactement autant de fois qu'il est entré dans ce mode. Si un thread essaie de quitter un mode trop de fois, ou de quitter un mode dans lequel il n'est pas entré, une exception SynchronizationLockException est levée.

États de verrouillage

Il peut être utile de penser au verrou en fonction de ses états. Un ReaderWriterLockSlim peut avoir l'un des quatre états suivants : non entré, lecture, mise à niveau et écriture.

  • Non entré : aucun thread n'a entré le verrou (ou tous les threads ont quitté le verrou).

  • Lecture : un ou plusieurs threads ont entré le verrou pour l'accès en lecture à la ressource protégée.

    Remarque Remarque

    Un thread peut entrer le verrou en mode lecture en utilisant les méthodes EnterReadLock ou TryEnterReadLock, ou en rétrogradant à partir du mode de mise à niveau.

  • Mise à niveau : un thread a entré le verrou pour l'accès en lecture avec l'option de mise à niveau avec accès en écriture (autrement dit, en mode de mise à niveau), et aucun ou plusieurs threads ont entré le verrou pour l'accès en lecture. Un seul thread à la fois peut entrer le verrou avec l'option de mise à niveau ; les autres threads qui essaient d'entrer en mode de mise à niveau sont bloqués.

  • Écriture : un thread a entré le verrou pour l'accès en écriture à la ressource protégée. Ce thread a la propriété exclusive du verrou. Tout autre thread qui essaie d'entrer le verrou pour une raison quelconque est bloqué.

Le tableau suivant décrit les transitions entre états de verrou, pour les verrous qui n'autorisent pas la récurrence, lorsqu'un thread t exécute l'action décrite dans la colonne de gauche. Au moment de l'action, t n'a aucun mode. (Le cas spécial où t est en mode de mise à niveau est décrit dans les notes de bas de page du tableau.) La rangée supérieure décrit l'état initial du verrou. Les cellules décrivent ce qui arrive au thread et affichent les modifications de l'état du verrou entre parenthèses.

Non entré (N)

Lire (R)

Mettre à niveau (U)

Écrire (W)

t entre en mode lecture

t entre (R).

t bloque si les threads attendent le mode écriture ; sinon, t entre.

t bloque si les threads attendent le mode écriture ; sinon, t entre.1

t bloque.

t entre en mode de mise à niveau

t entre (U).

t bloque si les threads attendent le mode écriture ou le mode de mise à niveau; sinon, t entre (U).

t bloque.

t bloque.

t entre en mode écriture

t entre (W).

t bloque.

t bloque.2

t bloque.

1 Si t commence à partir du mode de mise à niveau, il entre en mode lecture. Cette action ne bloque jamais. L'état du verrou ne change pas. (Le thread peut ensuite terminer une rétrogradation vers le mode lecture en quittant le mode de mise à niveau.)

2 Si t commence à partir du mode de mise à niveau, il bloque si des threads sont en mode lecture. Sinon, il effectue une mise à niveau vers le mode écriture. L'état du verrou passe à Écriture (W). Si t bloque parce qu'il y a des threads en mode lecture, il entre en mode écriture dès que le dernier thread quitte le mode lecture, même si des threads attendent pour entrer en mode écriture.

Lorsqu'une modification d'état se produit parce qu'un thread quitte le verrou, le thread actif suivant est sélectionné comme suit :

  • En premier lieu, un thread qui attend le mode écriture et est déjà en mode de mise à niveau (il ne peut y en avoir qu'un seul).

  • En l'absence d'un thread de ce type, un thread qui attend le mode écriture.

  • En l'absence d'un thread de ce type, un thread qui attend le mode de mise à niveau.

  • En l'absence d'un thread de ce type, tous les threads qui attendent le mode lecture.

L'état suivant du verrou est toujours Écriture (W) dans les deux premiers cas et Mise à niveau (U) dans le troisième cas, indépendamment de l'état du verrou lorsque le thread sortant a déclenché la modification d'état. Dans le dernier cas, l'état du verrou est Mise à niveau (U) s'il y a un thread en mode mise à niveau après la modification d'état, et Lecture (R) sinon, quel que soit l'état antérieur.

Remarque Remarque

L'attribut HostProtectionAttribute appliqué à ce type ou membre a la valeur de propriété Resources suivante : MayLeakOnAbort | 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 présente un cache synchronisé simple qui stocke des chaînes avec des clés entières. Une instance de ReaderWriterLockSlim est utilisée pour synchroniser l'accès au Dictionary<TKey, TValue> qui sert de cache interne.

L'exemple inclut des méthodes simples pour ajouter au cache, supprimer du cache et lire dans le cache. Pour illustrer les délais d'attente, l'exemple inclut une méthode qui ajoute au cache uniquement s'il peut le faire dans le délai d'attente spécifié.

Pour présenter le mode de mise à niveau, l'exemple inclut une méthode qui récupère la valeur associée à une clé et la compare avec une nouvelle valeur. Si la valeur est inchangée, la méthode retourne un état qui n'indique aucune modification. Si aucune valeur n'est trouvée pour la clé, la paire clé/valeur est insérée. Si la valeur a changé, elle est mise à jour. Le mode de mise à niveau permet au thread d'effectuer une mise à niveau de l'accès en lecture vers l'accès en écriture en fonction des besoins, sans risque d'interblocage.

L'exemple inclut une énumération imbriquée qui spécifie les valeurs de retour pour la méthode présentant le mode de mise à niveau.

L'exemple utilise le constructeur par défaut pour créer le verrou, donc la récurrence n'est pas autorisée. La programmation de ReaderWriterLockSlim est plus simple et moins risquée lorsque le verrou n'autorise pas la récurrence.


using System;
using System.Threading;
using System.Collections.Generic;

public class SynchronizedCache
{
    private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
    private Dictionary<int, string> innerCache = new Dictionary<int, string>();

    public string Read(int key)
    {
        cacheLock.EnterReadLock();
        try
        {
            return innerCache[key];
        }
        finally
        {
            cacheLock.ExitReadLock();
        }
    }

    public void Add(int key, string value)
    {
        cacheLock.EnterWriteLock();
        try
        {
            innerCache.Add(key, value);
        }
        finally
        {
            cacheLock.ExitWriteLock();
        }
    }

    public bool AddWithTimeout(int key, string value, int timeout)
    {
        if (cacheLock.TryEnterWriteLock(timeout))
        {
            try
            {
                innerCache.Add(key, value);
            }
            finally
            {
                cacheLock.ExitWriteLock();
            }
            return true;
        }
        else
        {
            return false;
        }
    }

    public AddOrUpdateStatus AddOrUpdate(int key, string value)
    {
        cacheLock.EnterUpgradeableReadLock();
        try
        {
            string result = null;
            if (innerCache.TryGetValue(key, out result))
            {
                if (result == value)
                {
                    return AddOrUpdateStatus.Unchanged;
                }
                else
                {
                    cacheLock.EnterWriteLock();
                    try
                    {
                        innerCache[key] = value;
                    }
                    finally
                    {
                        cacheLock.ExitWriteLock();
                    }
                    return AddOrUpdateStatus.Updated;
                }
            }
            else
            {
                cacheLock.EnterWriteLock();
                try
                {
                    innerCache.Add(key, value);
                }
                finally
                {
                    cacheLock.ExitWriteLock();
                }
                return AddOrUpdateStatus.Added;
            }
        }
        finally
        {
            cacheLock.ExitUpgradeableReadLock();
        }
    }

    public void Delete(int key)
    {
        cacheLock.EnterWriteLock();
        try
        {
            innerCache.Remove(key);
        }
        finally
        {
            cacheLock.ExitWriteLock();
        }
    }

    public enum AddOrUpdateStatus
    {
        Added,
        Updated,
        Unchanged
    };
}


.NET Framework

Pris en charge dans : 4, 3.5

.NET Framework Client Profile

Pris en charge dans : 4, 3.5 SP1

Windows 7, Windows Vista SP1 ou ultérieur, Windows XP SP3, 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.

Ce type est thread-safe.

Cela vous a-t-il été utile ?
(1500 caractères restants)
Contenu de la communauté Ajouter
Annotations FAQ