Partager via


Interlocked Classe

Définition

Fournit des opérations atomiques pour les variables partagées par plusieurs threads.

public ref class Interlocked abstract sealed
public ref class Interlocked sealed
public static class Interlocked
public sealed class Interlocked
type Interlocked = class
Public Class Interlocked
Public NotInheritable Class Interlocked
Héritage
Interlocked

Exemples

L’exemple de code suivant montre un mécanisme de verrouillage de ressources thread-safe.

using namespace System;
using namespace System::Threading;

const int numThreads = 10;
const int numThreadIterations = 5;
ref class MyInterlockedExchangeExampleClass
{
public:
   static void MyThreadProc()
   {
      for ( int i = 0; i < numThreadIterations; i++ )
      {
         UseResource();
         
         //Wait 1 second before next attempt.
         Thread::Sleep( 1000 );

      }
   }


private:
   //A simple method that denies reentrancy.
   static bool UseResource()
   {
      
      //0 indicates that the method is not in use.
      if ( 0 == Interlocked::Exchange( usingResource, 1 ) )
      {
         Console::WriteLine( " {0} acquired the lock", Thread::CurrentThread->Name );
         
         //Code to access a resource that is not thread safe would go here.
         //Simulate some work
         Thread::Sleep( 500 );
         Console::WriteLine( " {0} exiting lock", Thread::CurrentThread->Name );
         
         //Release the lock
         Interlocked::Exchange( usingResource, 0 );
         return true;
      }
      else
      {
         Console::WriteLine( " {0} was denied the lock", Thread::CurrentThread->Name );
         return false;
      }
   }


   //0 for false, 1 for true.
   static int usingResource;
};

int main()
{
   Thread^ myThread;
   Random^ rnd = gcnew Random;
   for ( int i = 0; i < numThreads; i++ )
   {
      myThread = gcnew Thread( gcnew ThreadStart( MyInterlockedExchangeExampleClass::MyThreadProc ) );
      myThread->Name = String::Format( "Thread {0}", i + 1 );
      
      //Wait a random amount of time before starting next thread.
      Thread::Sleep( rnd->Next( 0, 1000 ) );
      myThread->Start();

   }
}
using System;
using System.Threading;

namespace InterlockedExchange_Example
{
    class MyInterlockedExchangeExampleClass
    {
        //0 for false, 1 for true.
        private static int usingResource = 0;

        private const int numThreadIterations = 5;
        private const int numThreads = 10;

        static void Main()
        {
            Thread myThread;
            Random rnd = new Random();

            for(int i = 0; i < numThreads; i++)
            {
                myThread = new Thread(new ThreadStart(MyThreadProc));
                myThread.Name = String.Format("Thread{0}", i + 1);
            
                //Wait a random amount of time before starting next thread.
                Thread.Sleep(rnd.Next(0, 1000));
                myThread.Start();
            }
        }

        private static void MyThreadProc()
        {
            for(int i = 0; i < numThreadIterations; i++)
            {
                UseResource();
            
                //Wait 1 second before next attempt.
                Thread.Sleep(1000);
            }
        }

        //A simple method that denies reentrancy.
        static bool UseResource()
        {
            //0 indicates that the method is not in use.
            if(0 == Interlocked.Exchange(ref usingResource, 1))
            {
                Console.WriteLine("{0} acquired the lock", Thread.CurrentThread.Name);
            
                //Code to access a resource that is not thread safe would go here.
            
                //Simulate some work
                Thread.Sleep(500);

                Console.WriteLine("{0} exiting lock", Thread.CurrentThread.Name);
            
                //Release the lock
                Interlocked.Exchange(ref usingResource, 0);
                return true;
            }
            else
            {
                Console.WriteLine("   {0} was denied the lock", Thread.CurrentThread.Name);
                return false;
            }
        }
    }
}
Imports System.Threading

Namespace InterlockedExchange_Example
    Class MyInterlockedExchangeExampleClass
        '0 for false, 1 for true.
        Private Shared usingResource As Integer = 0

        Private Const numThreadIterations As Integer = 5
        Private Const numThreads As Integer = 10

        <MTAThread> _
        Shared Sub Main()
            Dim myThread As Thread
            Dim rnd As New Random()

            Dim i As Integer
            For i = 0 To numThreads - 1
                myThread = New Thread(AddressOf MyThreadProc)
                myThread.Name = String.Format("Thread{0}", i + 1)

                'Wait a random amount of time before starting next thread.
                Thread.Sleep(rnd.Next(0, 1000))
                myThread.Start()
            Next i
        End Sub

        Private Shared Sub MyThreadProc()
            Dim i As Integer
            For i = 0 To numThreadIterations - 1
                UseResource()

                'Wait 1 second before next attempt.
                Thread.Sleep(1000)
            Next i
        End Sub 

        'A simple method that denies reentrancy.
        Shared Function UseResource() As Boolean
            '0 indicates that the method is not in use.
            If 0 = Interlocked.Exchange(usingResource, 1) Then
                Console.WriteLine("{0} acquired the lock", Thread.CurrentThread.Name)

                'Code to access a resource that is not thread safe would go here.
                'Simulate some work
                Thread.Sleep(500)

                Console.WriteLine("{0} exiting lock", Thread.CurrentThread.Name)

                'Release the lock
                Interlocked.Exchange(usingResource, 0)
                Return True
            Else
                Console.WriteLine("   {0} was denied the lock", Thread.CurrentThread.Name)
                Return False
            End If
        End Function 
    End Class 
End Namespace

Remarques

Les méthodes de cette classe permettent de protéger contre les erreurs qui peuvent se produire lorsque le planificateur bascule des contextes pendant qu’un thread met à jour une variable accessible par d’autres threads, ou lorsque deux threads s’exécutent simultanément sur des processeurs distincts. Les membres de cette classe ne lèvent pas d’exceptions.

Les méthodes Increment et Decrement incrémentent ou décrémentent une variable et stockent la valeur résultante dans une seule opération. Sur la plupart des ordinateurs, l’incrémentation d’une variable n’est pas une opération atomique, ce qui nécessite les étapes suivantes :

  1. Chargez une valeur à partir d’une variable d’instance dans un registre.

  2. Incrémentez ou décrémentez la valeur.

  3. Stockez la valeur dans la variable d’instance.

Si vous n’utilisez pas Increment et Decrement, un thread peut être préempté après l’exécution des deux premières étapes. Un autre thread peut ensuite exécuter les trois étapes. Lorsque le premier thread reprend l’exécution, il remplace la valeur dans la variable d’instance et l’effet de l’incrément ou de la décrémentation effectuée par le deuxième thread est perdu.

La méthode Add ajoute atomiquement une valeur entière à une variable entière et retourne la nouvelle valeur de la variable.

La méthode Exchange échange atomiquement les valeurs des variables spécifiées. La méthode CompareExchange combine deux opérations : comparer deux valeurs et stocker une troisième valeur dans l’une des variables, en fonction du résultat de la comparaison. Les opérations de comparaison et d’échange sont effectuées en tant qu’opération atomique.

Vérifiez que tout accès en écriture ou en lecture à une variable partagée est atomique. Sinon, les données peuvent être endommagées ou la valeur chargée peut être incorrecte.

Méthodes

Add(Int32, Int32)

Ajoute deux entiers 32 bits et remplace le premier entier par la somme, en tant qu’opération atomique.

Add(Int64, Int64)

Ajoute deux entiers 64 bits et remplace le premier entier par la somme, en tant qu’opération atomique.

Add(UInt32, UInt32)

Ajoute deux entiers non signés 32 bits et remplace le premier entier par la somme, en tant qu’opération atomique.

Add(UInt64, UInt64)

Ajoute deux entiers non signés 64 bits et remplace le premier entier par la somme, en tant qu’opération atomique.

And(Int32, Int32)

Au niveau du bit, deux entiers signés 32 bits et remplacent le premier entier par le résultat, en tant qu’opération atomique.

And(Int64, Int64)

Au niveau du bit , deux entiers signés 64 bits et remplace le premier entier par le résultat, sous la forme d’une opération atomique.

And(UInt32, UInt32)

Au niveau du bit , deux entiers non signés 32 bits et remplace le premier entier par le résultat, sous la forme d’une opération atomique.

And(UInt64, UInt64)

Au niveau du bit , deux entiers non signés 64 bits et remplace le premier entier par le résultat, sous la forme d’une opération atomique.

CompareExchange(Byte, Byte, Byte)

Compare deux entiers non signés 8 bits pour l’égalité et, s’ils sont égaux, remplace la première valeur.

CompareExchange(Double, Double, Double)

Compare deux nombres à virgule flottante double précision pour l’égalité et, s’ils sont égaux, remplace la première valeur.

CompareExchange(Int16, Int16, Int16)

Compare deux entiers non signés 16 bits pour l’égalité et, s’ils sont égaux, remplace la première valeur.

CompareExchange(Int32, Int32, Int32)

Compare deux entiers signés 32 bits pour l’égalité et, s’ils sont égaux, remplace la première valeur.

CompareExchange(Int64, Int64, Int64)

Compare deux entiers signés 64 bits pour l’égalité et, s’ils sont égaux, remplace la première valeur.

CompareExchange(IntPtr, IntPtr, IntPtr)

Compare deux handles ou pointeurs spécifiques à la plateforme pour l’égalité et, s’ils sont égaux, remplace le premier.

CompareExchange(Object, Object, Object)

Compare deux objets pour l’égalité de référence et, s’ils sont égaux, remplace le premier objet.

CompareExchange(SByte, SByte, SByte)

Compare deux entiers signés 8 bits pour l’égalité et, s’ils sont égaux, remplace la première valeur.

CompareExchange(Single, Single, Single)

Compare deux nombres à virgule flottante simple précision pour l’égalité et, s’ils sont égaux, remplace la première valeur.

CompareExchange(UInt16, UInt16, UInt16)

Compare deux entiers signés 16 bits pour l’égalité et, s’ils sont égaux, remplace la première valeur.

CompareExchange(UInt32, UInt32, UInt32)

Compare deux entiers non signés 32 bits pour l’égalité et, s’ils sont égaux, remplace la première valeur.

CompareExchange(UInt64, UInt64, UInt64)

Compare deux entiers non signés 64 bits pour l’égalité et, s’ils sont égaux, remplace la première valeur.

CompareExchange(UIntPtr, UIntPtr, UIntPtr)

Compare deux handles ou pointeurs spécifiques à la plateforme pour l’égalité et, s’ils sont égaux, remplace le premier.

CompareExchange<T>(T, T, T)

Compare deux instances du type de référence spécifié T pour l’égalité de référence et, s’ils sont égaux, remplace le premier.

Decrement(Int32)

Décrémente une variable spécifiée et stocke le résultat, en tant qu’opération atomique.

Decrement(Int64)

Décrémente la variable spécifiée et stocke le résultat, en tant qu’opération atomique.

Decrement(UInt32)

Décrémente une variable spécifiée et stocke le résultat, en tant qu’opération atomique.

Decrement(UInt64)

Décrémente une variable spécifiée et stocke le résultat, en tant qu’opération atomique.

Exchange(Byte, Byte)

Définit un entier non signé 8 bits sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange(Double, Double)

Définit un nombre à virgule flottante double précision sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange(Int16, Int16)

Définit un entier non signé 16 bits sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange(Int32, Int32)

Définit un entier signé 32 bits sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange(Int64, Int64)

Définit un entier signé 64 bits sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange(IntPtr, IntPtr)

Définit un handle ou un pointeur spécifique à la plateforme sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange(Object, Object)

Définit un objet sur une valeur spécifiée et retourne une référence à l’objet d’origine, en tant qu’opération atomique.

Exchange(SByte, SByte)

Définit un entier signé 8 bits sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange(Single, Single)

Définit un nombre à virgule flottante simple précision sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange(UInt16, UInt16)

Définit un entier signé 16 bits sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange(UInt32, UInt32)

Définit un entier non signé 32 bits sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange(UInt64, UInt64)

Définit un entier non signé 64 bits sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange(UIntPtr, UIntPtr)

Définit un handle ou un pointeur spécifique à la plateforme sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Exchange<T>(T, T)

Définit une variable du type spécifié T sur une valeur spécifiée et retourne la valeur d’origine, en tant qu’opération atomique.

Increment(Int32)

Incrémente une variable spécifiée et stocke le résultat, en tant qu’opération atomique.

Increment(Int64)

Incrémente une variable spécifiée et stocke le résultat, en tant qu’opération atomique.

Increment(UInt32)

Incrémente une variable spécifiée et stocke le résultat, en tant qu’opération atomique.

Increment(UInt64)

Incrémente une variable spécifiée et stocke le résultat, en tant qu’opération atomique.

MemoryBarrier()

Synchronise l’accès à la mémoire comme suit : le processeur qui exécute le thread actuel ne peut pas réorganiser les instructions de telle façon que la mémoire accède avant l’appel à MemoryBarrier() s’exécuter après les accès à la mémoire qui suivent l’appel à MemoryBarrier().

MemoryBarrierProcessWide()

Fournit une barrière de mémoire à l’échelle du processus qui garantit que les lectures et les écritures à partir de n’importe quel processeur ne peuvent pas se déplacer sur la barrière.

Or(Int32, Int32)

Au niveau du bit, deux entiers signés 32 bits et remplace le premier entier par le résultat, en tant qu’opération atomique.

Or(Int64, Int64)

Au niveau du bit, deux entiers signés 64 bits et remplace le premier entier par le résultat, en tant qu’opération atomique.

Or(UInt32, UInt32)

Au niveau du bit , deux entiers non signés 32 bits et remplacent le premier entier par le résultat, sous la forme d’une opération atomique.

Or(UInt64, UInt64)

Au niveau du bit , deux entiers non signés 64 bits et remplace le premier entier par le résultat, sous la forme d’une opération atomique.

Read(Int64)

Retourne une valeur 64 bits, chargée en tant qu’opération atomique.

Read(UInt64)

Retourne une valeur non signée 64 bits, chargée en tant qu’opération atomique.

SpeculationBarrier()

Définit une clôture de mémoire qui bloque l’exécution spéculative au-delà de ce point jusqu’à ce que les lectures et écritures en attente soient terminées.

S’applique à

Cohérence de thread

Ce type est thread safe.

Voir aussi