lock-Anweisung (C#-Referenz)lock statement (C# Reference)

Die lock-Anweisung ruft die Sperre für gegenseitigen Ausschluss für ein bestimmtes Objekt ab, führt einen Anweisungsblock aus und hebt die Sperre anschließend auf.The lock statement acquires the mutual-exclusion lock for a given object, executes a statement block, and then releases the lock. Während eine Sperre aufrechterhalten wird, kann der Thread, der die Sperre aufrechterhält, die Sperre abrufen und aufheben.While a lock is held, the thread that holds the lock can again acquire and release the lock. Für jeden anderen Thread wird das Abrufen der Sperre blockiert, und die Sperre wartet auf die Aufhebung.Any other thread is blocked from acquiring the lock and waits until the lock is released.

Die lock-Anweisung weist folgendes Format auf:The lock statement is of the form

lock (x)
{
    // Your code...
}

x entspricht einem Ausdruck eines Verweistyps.where x is an expression of a reference type. Dieser entspricht exakt Folgendem:It's precisely equivalent to

object __lockObj = x;
bool __lockWasTaken = false;
try
{
    System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
    // Your code...
}
finally
{
    if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}

Da ein try...finally-Block in diesem Code verwendet wird, wird die Sperre aufgehoben, wenn eine Ausnahme innerhalb des Texts einer lock-Anweisung ausgelöst wird.Since the code uses a try...finally block, the lock is released even if an exception is thrown within the body of a lock statement.

Sie können das Schlüsselwort await nicht im Text einer lock-Anweisung verwenden.You can't use the await keyword in the body of a lock statement.

HinweiseRemarks

Wenn Sie den Threadzugriff auf eine freigegebene Ressource synchronisieren, sperren Sie eine dedizierte Objektinstanz (z.B. private readonly object balanceLock = new object();) oder eine andere Instanz, die wahrscheinlich nicht von anderen Teilen des Codes als lock-Objekt verwendet wird.When you synchronize thread access to a shared resource, lock on a dedicated object instance (for example, private readonly object balanceLock = new object();) or another instance that is unlikely to be used as a lock object by unrelated parts of the code. Vermeiden Sie, die gleiche lock-Objektinstanz für verschiedene freigegebene Ressourcen zu verwenden, da dies zu einem Deadlock oder Sperrkonflikt führen kann.Avoid using the same lock object instance for different shared resources, as it might result in deadlock or lock contention. Vermeiden Sie insbesondere die Verwendung der folgenden Objekte als Sperre:In particular, avoid using the following as lock objects:

  • this – kann von den Aufrufern als Sperre verwendet werden.this, as it might be used by the callers as a lock.
  • Type-Instanzen – können vom typeof-Operator oder der Reflektion abgerufen werden.Type instances, as those might be obtained by the typeof operator or reflection.
  • Zeichenfolgeninstanzen, einschließlich Zeichenfolgenliteralen – können internalisiert sein.string instances, including string literals, as those might be interned.

BeispielExample

Im folgenden Beispiel wird eine Account-Klasse definiert, die den Zugriff auf das private balance-Feld synchronisiert, indem eine dedizierte balanceLock-Instanz gesperrt wird.The following example defines an Account class that synchronizes access to its private balance field by locking on a dedicated balanceLock instance. Durch Verwendung der gleichen Instanz für die Sperre wird sichergestellt, dass das balance-Feld nicht von zwei Threads gleichzeitig aktualisiert werden kann, die zur gleichen Zeit versuchen, die Methoden Debit oder Credit aufzurufen.Using the same instance for locking ensures that the balance field cannot be updated simultaneously by two threads attempting to call the Debit or Credit methods simultaneously.

using System;
using System.Threading.Tasks;

public class Account
{
    private readonly object balanceLock = new object();
    private decimal balance;

    public Account(decimal initialBalance)
    {
        balance = initialBalance;
    }

    public decimal Debit(decimal amount)
    {
        lock (balanceLock)
        {
            if (balance >= amount)
            {
                Console.WriteLine($"Balance before debit :{balance, 5}");
                Console.WriteLine($"Amount to remove     :{amount, 5}");
                balance = balance - amount;
                Console.WriteLine($"Balance after debit  :{balance, 5}");
                return amount;
            }
            else
            {
                return 0;
            }
        }
    }

    public void Credit(decimal amount)
    {
        lock (balanceLock)
        {
            Console.WriteLine($"Balance before credit:{balance, 5}");
            Console.WriteLine($"Amount to add        :{amount, 5}");
            balance = balance + amount;
            Console.WriteLine($"Balance after credit :{balance, 5}");
        }
    }
}

class AccountTest
{
    static void Main()
    {
        var account = new Account(1000);
        var tasks = new Task[100];
        for (int i = 0; i < tasks.Length; i++)
        {
            tasks[i] = Task.Run(() => RandomlyUpdate(account));
        }
        Task.WaitAll(tasks);
    }

    static void RandomlyUpdate(Account account)
    {
        var rnd = new Random();
        for (int i = 0; i < 10; i++)
        {
            var amount = rnd.Next(1, 100);
            bool doCredit = rnd.NextDouble() < 0.5;
            if (doCredit)
            {
                account.Credit(amount);
            }
            else
            {
                account.Debit(amount);
            }
        }
    }
}

C#-SprachspezifikationC# language specification

Weitere Informationen erhalten Sie unter C#-Sprachspezifikation.For more information, see the C# Language Specification. Die Sprachspezifikation ist die verbindliche Quelle für die Syntax und Verwendung von C#.The language specification is the definitive source for C# syntax and usage.

Siehe auchSee also