Condividi tramite


Interlocked Classe

Definizione

Fornisce operazioni atomiche per le variabili condivise da più thread.

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
Ereditarietà
Interlocked

Esempio

L'esempio di codice seguente illustra un meccanismo di blocco delle risorse 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

Commenti

I metodi di questa classe consentono di proteggere da errori che possono verificarsi quando l'utilità di pianificazione cambia i contesti mentre un thread aggiorna una variabile a cui è possibile accedere da altri thread o quando due thread vengono eseguiti simultaneamente in processori separati. I membri di questa classe non generano eccezioni.

I metodi Increment e Decrement incrementano o decrementano una variabile e archiviano il valore risultante in una singola operazione. Nella maggior parte dei computer, l'incremento di una variabile non è un'operazione atomica, che richiede i passaggi seguenti:

  1. Caricare un valore da una variabile di istanza in un registro.

  2. Incrementare o decrementare il valore.

  3. Archiviare il valore nella variabile di istanza.

Se non si usano Increment e Decrement, è possibile interrompere un thread dopo aver eseguito i primi due passaggi. Un altro thread può quindi eseguire tutti e tre i passaggi. Quando il primo thread riprende l'esecuzione, sovrascrive il valore nella variabile di istanza e l'effetto dell'incremento o del decremento eseguito dal secondo thread viene perso.

Il metodo Add aggiunge atomicamente un valore intero a una variabile integer e restituisce il nuovo valore della variabile.

Il metodo Exchange scambia in modo atomico i valori delle variabili specificate. Il metodo CompareExchange combina due operazioni: confronto di due valori e archiviazione di un terzo valore in una delle variabili, in base al risultato del confronto. Le operazioni di confronto e scambio vengono eseguite come operazione atomica.

Assicurarsi che qualsiasi accesso in scrittura o lettura a una variabile condivisa sia atomico. In caso contrario, i dati potrebbero essere danneggiati o il valore caricato potrebbe non essere corretto.

Metodi

Add(Int32, Int32)

Aggiunge due interi a 32 bit e sostituisce il primo intero con la somma, come operazione atomica.

Add(Int64, Int64)

Aggiunge due interi a 64 bit e sostituisce il primo intero con la somma, come operazione atomica.

Add(UInt32, UInt32)

Aggiunge due interi senza segno a 32 bit e sostituisce il primo intero con la somma, come operazione atomica.

Add(UInt64, UInt64)

Aggiunge due interi senza segno a 64 bit e sostituisce il primo intero con la somma, come operazione atomica.

And(Int32, Int32)

"ands" bit per bit due interi con segno a 32 bit e sostituisce il primo intero con il risultato, come operazione atomica.

And(Int64, Int64)

"ands" bit per bit due interi con segno a 64 bit e sostituisce il primo intero con il risultato, come operazione atomica.

And(UInt32, UInt32)

"ands" bit per bit due interi senza segno a 32 bit e sostituisce il primo intero con il risultato, come operazione atomica.

And(UInt64, UInt64)

"ands" bit per bit due interi senza segno a 64 bit e sostituisce il primo intero con il risultato, come operazione atomica.

CompareExchange(Byte, Byte, Byte)

Confronta due interi senza segno a 8 bit per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo valore come operazione atomica.

CompareExchange(Double, Double, Double)

Confronta due numeri a virgola mobile a precisione doppia per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo valore come operazione atomica.

CompareExchange(Int16, Int16, Int16)

Confronta due interi senza segno a 16 bit per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo valore come operazione atomica.

CompareExchange(Int32, Int32, Int32)

Confronta due interi con segno a 32 bit per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo valore come operazione atomica.

CompareExchange(Int64, Int64, Int64)

Confronta due interi con segno a 64 bit per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo valore come operazione atomica.

CompareExchange(IntPtr, IntPtr, IntPtr)

Confronta due handle o puntatori specifici della piattaforma per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo come operazione atomica.

CompareExchange(Object, Object, Object)

Confronta due oggetti per l'uguaglianza dei riferimenti e, se sono uguali, sostituisce il primo oggetto come operazione atomica.

CompareExchange(SByte, SByte, SByte)

Confronta due interi con segno a 8 bit per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo valore come operazione atomica.

CompareExchange(Single, Single, Single)

Confronta due numeri a virgola mobile a precisione singola per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo valore come operazione atomica.

CompareExchange(UInt16, UInt16, UInt16)

Confronta due interi con segno a 16 bit per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo valore come operazione atomica.

CompareExchange(UInt32, UInt32, UInt32)

Confronta due interi senza segno a 32 bit per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo valore come operazione atomica.

CompareExchange(UInt64, UInt64, UInt64)

Confronta due interi senza segno a 64 bit per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo valore come operazione atomica.

CompareExchange(UIntPtr, UIntPtr, UIntPtr)

Confronta due handle o puntatori specifici della piattaforma per verificarne l'uguaglianza e, se sono uguali, sostituisce il primo come operazione atomica.

CompareExchange<T>(T, T, T)

Confronta due istanze del tipo di riferimento specificato T per l'uguaglianza dei riferimenti e, se sono uguali, sostituisce la prima come operazione atomica.

Decrement(Int32)

Decrementa una variabile specificata e archivia il risultato, come operazione atomica.

Decrement(Int64)

Decrementa la variabile specificata e archivia il risultato, come operazione atomica.

Decrement(UInt32)

Decrementa una variabile specificata e archivia il risultato, come operazione atomica.

Decrement(UInt64)

Decrementa una variabile specificata e archivia il risultato, come operazione atomica.

Exchange(Byte, Byte)

Imposta un intero senza segno a 8 bit su un valore specificato e restituisce il valore originale, come operazione atomica.

Exchange(Double, Double)

Imposta un numero a virgola mobile a precisione doppia su un valore specificato e restituisce il valore originale, come operazione atomica.

Exchange(Int16, Int16)

Imposta un intero senza segno a 16 bit su un valore specificato e restituisce il valore originale come operazione atomica.

Exchange(Int32, Int32)

Imposta un intero con segno a 32 bit su un valore specificato e restituisce il valore originale, come operazione atomica.

Exchange(Int64, Int64)

Imposta un intero con segno a 64 bit su un valore specificato e restituisce il valore originale, come operazione atomica.

Exchange(IntPtr, IntPtr)

Imposta un handle o un puntatore specifico della piattaforma su un valore specificato e restituisce il valore originale, come operazione atomica.

Exchange(Object, Object)

Imposta un oggetto su un valore specificato e restituisce un riferimento all'oggetto originale, come operazione atomica.

Exchange(SByte, SByte)

Imposta un intero con segno a 8 bit su un valore specificato e restituisce il valore originale, come operazione atomica.

Exchange(Single, Single)

Imposta un numero a virgola mobile a precisione singola su un valore specificato e restituisce il valore originale come operazione atomica.

Exchange(UInt16, UInt16)

Imposta un intero con segno a 16 bit su un valore specificato e restituisce il valore originale, come operazione atomica.

Exchange(UInt32, UInt32)

Imposta un intero senza segno a 32 bit su un valore specificato e restituisce il valore originale come operazione atomica.

Exchange(UInt64, UInt64)

Imposta un intero senza segno a 64 bit su un valore specificato e restituisce il valore originale come operazione atomica.

Exchange(UIntPtr, UIntPtr)

Imposta un handle o un puntatore specifico della piattaforma su un valore specificato e restituisce il valore originale, come operazione atomica.

Exchange<T>(T, T)

Imposta una variabile del tipo specificato T su un valore specificato e restituisce il valore originale, come operazione atomica.

Increment(Int32)

Incrementa una variabile specificata e archivia il risultato, come operazione atomica.

Increment(Int64)

Incrementa una variabile specificata e archivia il risultato, come operazione atomica.

Increment(UInt32)

Incrementa una variabile specificata e archivia il risultato, come operazione atomica.

Increment(UInt64)

Incrementa una variabile specificata e archivia il risultato, come operazione atomica.

MemoryBarrier()

Sincronizza l'accesso alla memoria nel modo seguente: il processore che esegue il thread corrente non può riordinare le istruzioni in modo che la memoria accesa prima della chiamata a MemoryBarrier() eseguire dopo gli accessi alla memoria che seguono la chiamata a MemoryBarrier().

MemoryBarrierProcessWide()

Fornisce una barriera di memoria a livello di processo che garantisce che le letture e le scritture da qualsiasi CPU non possano spostarsi attraverso la barriera.

Or(Int32, Int32)

"ors" bit per bit due interi con segno a 32 bit e sostituisce il primo intero con il risultato, come operazione atomica.

Or(Int64, Int64)

"ors" bit per bit due interi con segno a 64 bit e sostituisce il primo intero con il risultato, come operazione atomica.

Or(UInt32, UInt32)

"ors" bit per bit due interi senza segno a 32 bit e sostituisce il primo intero con il risultato, come operazione atomica.

Or(UInt64, UInt64)

"ors" bit per bit due interi senza segno a 64 bit e sostituisce il primo intero con il risultato, come operazione atomica.

Read(Int64)

Restituisce un valore a 64 bit, caricato come operazione atomica.

Read(UInt64)

Restituisce un valore senza segno a 64 bit, caricato come operazione atomica.

SpeculationBarrier()

Definisce un limite di memoria che blocca l'esecuzione speculativa oltre questo punto fino al completamento delle letture e delle scritture in sospeso.

Si applica a

Thread safety

Questo tipo è thread-safe.

Vedi anche