Partilhar via


Operações interligadas

The Interlocked classe fornece métodos sincronizar o acesso a uma variável que é compartilhado por vários threads. Os threads de processos diferentes podem usar esse mecanismo se a variável estiver na memória compartilhada.Operações interligadas são atômicas — ou seja, toda a operação é uma unidade que não pode ser interrompida por outra operação interligada na mesma variável.Isso é importante nos sistemas operacionais com preventivo multithreading, onde um segmento pode ser suspenso depois de carregar um valor de um endereço de memória, mas antes de ter a chance de alterá-lo e armazená-lo.

The Interlocked classe fornece as seguintes operações:

  • No .NET estrutura versão 2.0, a Add método adiciona um valor inteiro a uma variável e retorna o novo valor da variável.

  • No .NET estrutura versão 2.0, a Read método lê um valor inteiro de 64 bit sistema autônomo uma operação atômica. Isso é útil em sistemas operacionais de 32 bit, onde um número inteiro de 64 bit de leitura não é normalmente uma operação atômica.

  • The Increment e Decrement métodos incrementam ou decrementam a uma variável e retornam o valor resultante.

  • The Exchange método realiza uma troca atômica do valor em uma variável especificada, esse valor de retorno e substituindo-o com um novo valor. No .NET estrutura versão 2.0, uma sobrecarga desse método genérica pode ser usada para realizar essa troca em uma variável de qualquer tipo de referência.Consulte Exchange<T>(T%, T).

  • The CompareExchange método também troca dois valores, mas contingente no resultado de uma comparação. No .NET estrutura versão 2.0, uma sobrecarga desse método genérica pode ser usada para realizar essa troca em uma variável de qualquer tipo de referência.Consulte CompareExchange<T>(T%, T, T).

Nos processadores modernos, os métodos do Interlocked classe muitas vezes pode ser implementada por uma única instrução. Dessa forma, eles oferecem alto desempenho sincronização e pode ser usados para criar mecanismos de sincronização de nível mais alto, como bloqueios de rotação.

Para obter um exemplo que usa o Monitor e Interlocked classes em combinação, consulte Monitores.

Exemplo da CompareExchange

The CompareExchange método pode ser usado para proteger os cálculos são mais complicados do que simples incremento e de decremento. O exemplo a seguir demonstra um método de thread-safe que adiciona um total contínuo armazenado sistema autônomo uma flutuante número de ponto.(Para inteiros, a Add método é uma solução mais simples.) Para obter exemplos de código completo, consulte os métodos sobrecarregados de CompareExchange que levar argumentos de ponto flutuante de precisão simples e precisão dupla)CompareExchange(Single%, Single, Single) e CompareExchange(Double%, Double, Double)).

Imports System.Threading

Public Class ThreadSafe
    ' Field totalValue contains a running total that can be updated
    ' by multiple threads. It must be protected from unsynchronized 
    ' access.
    Private totalValue As Double = 0.0

    ' The Total property returns the running total.
    Public ReadOnly Property Total As Double
        Get
            Return totalValue
        End Get
    End Property

    ' AddToTotal safely adds a value to the running total.
    Public Function AddToTotal(ByVal addend As Double) As Double
        Dim initialValue, computedValue As Double
        Do
            ' Save the current running total in a local variable.
            initialValue = totalValue

            ' Add the new value to the running total.
            computedValue = initialValue + addend

            ' CompareExchange compares totalValue to initialValue. If
            ' they are not equal, then another thread has updated the
            ' running total since this loop started. CompareExchange
            ' does not update totalValue. CompareExchange returns the
            ' contents of totalValue, which do not equal initialValue,
            ' so the loop executes again.
        Loop While initialValue <> Interlocked.CompareExchange( _
            totalValue, computedValue, initialValue)
        ' If no other thread updated the running total, then 
        ' totalValue and initialValue are equal when CompareExchange
        ' compares them, and computedValue is stored in totalValue.
        ' CompareExchange returns the value that was in totalValue
        ' before the update, which is equal to initialValue, so the 
        ' loop ends.

        ' The function returns computedValue, not totalValue, because
        ' totalValue could be changed by another thread between
        ' the time the loop ends and the function returns.
        Return computedValue
    End Function
End Class
using System.Threading;

public class ThreadSafe {
    // totalValue contains a running total that can be updated
    // by multiple threads. It must be protected from unsynchronized 
    // access.
    private double totalValue = 0;

    // The Total property returns the running total.
    public double Total {
        get { return totalValue; }
    }

    // AddToTotal safely adds a value to the running total.
    public double AddToTotal(double addend) {
        double initialValue, computedValue;
        do {
            // Save the current running total in a local variable.
            initialValue = totalValue;

            // Add the new value to the running total.
            computedValue = initialValue + addend;

            // CompareExchange compares totalValue to initialValue. If
            // they are not equal, then another thread has updated the
            // running total since this loop started. CompareExchange
            // does not update totalValue. CompareExchange returns the
            // contents of totalValue, which do not equal initialValue,
            // so the loop executes again.
        } while (initialValue != Interlocked.CompareExchange(
            ref totalValue, computedValue, initialValue));
        // If no other thread updated the running total, then 
        // totalValue and initialValue are equal when CompareExchange
        // compares them, and computedValue is stored in totalValue.
        // CompareExchange returns the value that was in totalValue
        // before the update, which is equal to initialValue, so the 
        // loop ends.

        // The function returns computedValue, not totalValue, because
        // totalValue could be changed by another thread between
        // the time the loop ends and the function returns.
        return computedValue;
    }
}

Sem tipo Overloads do Exchange e CompareExchange

The Exchange e CompareExchange métodos têm sobrecargas que obtém argumentos de tipo Object. O primeiro argumento de cada essas sobrecargas é ref Object (ByRef … As Object no Visual Basic), e tipo de segurança requer a variável passada para este argumento seja digitado estritamente sistema autônomo Object; Você simplesmente não é possível converter o primeiro argumento para digitar Object ao chamar esses métodos.

Observação:

No .NET estrutura versão 2.0, use os genéricos métodos sobrecarregados da Exchange e CompareExchange métodos para trocar altamente digitado variáveis.

O exemplo de código a seguir mostra uma propriedade do tipo ClassA que pode ser definida apenas uma vez, sistema autônomo pode ser implementado no .NET estrutura versão 1.0 ou 1.1.

Public Class ClassB
    ' The private field that stores the value for the
    ' ClassA property is intialized to Nothing. It is set
    ' once, from any of several threads. The field must
    ' be of type Object, so that CompareExchange can be
    ' used to assign the value. If the field is used
    ' within the body of class Test, it must be cast to
    ' type ClassA.
    Private classAValue As [Object] = Nothing
    ' This property can be set once to an instance of 
    ' ClassA. Attempts to set it again cause an
    ' exception to be thrown.
    
    Public Property ClassA() As ClassA
        Set
            ' CompareExchange compares the value in classAValue
            ' to Nothing. The new value assigned to the ClassA
            ' property, which is in the special variable 'value',
            ' is placed in classAValue only if classAValue is
            ' equal to Nothing.
            If Not (Nothing Is Interlocked.CompareExchange(classAValue, _
                    CType(value, [Object]), Nothing)) Then
                ' CompareExchange returns the original value of 
                ' classAValue; if it was not Nothing, then a value 
                ' was already assigned, and CompareExchange did not
                ' replace the original value. Throw an exception to
                ' indicate that an error occurred.
                Throw New ApplicationException("ClassA was already set.")
            End If
        End Set
        Get
            Return CType(classAValue, ClassA)
        End Get
    End Property
End Class ' ClassB
public class ClassB {
    // The private field that stores the value for the
    // ClassA property is intialized to null. It is set
    // once, from any of several threads. The field must
    // be of type Object, so that CompareExchange can be
    // used to assign the value. If the field is used
    // within the body of class Test, it must be cast to
    // type ClassA.
    private Object classAValue = null;
    // This property can be set once to an instance of 
    // ClassA. Attempts to set it again cause an
    // exception to be thrown.
    public ClassA ClassA {
        set {
            // CompareExchange compares the value in classAValue
            // to null. The new value assigned to the ClassA
            // property, which is in the special variable 'value',
            // is placed in classAValue only if classAValue is
            // equal to null.
            if (null != Interlocked.CompareExchange(ref classAValue,
                (Object) value, null)) {
                // CompareExchange returns the original value of 
                // classAValue; if it is not null, then a value 
                // was already assigned, and CompareExchange did not
                // replace the original value. Throw an exception to
                // indicate that an error occurred.
                throw new ApplicationException("ClassA was already set.");
            }
        }
        get {
            return (ClassA) classAValue;
        }
    }
}

Consulte também

Referência

Interlocked

Monitor

Outros recursos

Threads gerenciadas

Recursos e objetos de Threading