Synchronizacja wątku (C# i Visual Basic)

W poniższych sekcjach opisano funkcje i klas, które mogą być używane do synchronizowania dostępu do zasobów w aplikacjach wielowątkowych.

Jedną z zalet korzystania z wielu wątków w aplikacji jest, że każdy wątek będzie wykonywane asynchronicznie.Dla aplikacji systemu Windows dzięki temu czasochłonnych zadań wykonywanych w tle okna aplikacji, a formanty nadal odpowiadać.Dla serwera aplikacji wielowątkowość zapewnia możliwość obsługi każdego żądania przychodzące z innego wątku.W przeciwnym wypadku każde nowe żądanie byłoby get nie obsłużył aż poprzedniego żądania zostały w pełni spełnione.

Jednak charakter asynchronicznych wątków oznacza, że dostęp do zasobów, takich jak dojścia do plików, połączenia sieciowe i pamięci muszą być skoordynowane.W przeciwnym razie dwa lub więcej wątków można uzyskać dostępu tego samego zasobu w tym samym czasie, świadome każdego drugiego programu działań.Wynikiem jest uszkodzenie danych nieprzewidywalne.

Dla prostych operacji na typy danych liczbowych integralną synchronizacji wątków można wykonywać z członkami Interlocked klasy.Dla wszystkich innych danych typów i zasobów innych niż wielowątkowość, wielowątkowość można bezpiecznie wykonać tylko przy użyciu konstrukcji w tym temacie.

Aby uzyskać informacje ogólne na programowania wielowątkowego zobacz:

Zablokuj i SyncLock słów kluczowych.

lock (C#) i SyncLock instrukcji (Visual Basic) może służyć do zapewnienia, że blok kodu jest uruchamiane w celu zakończenia bez przerwy przez inne wątki.Można to osiągnąć poprzez uzyskanie blokady wzajemnego wykluczenia dla danego obiektu na czas trwania bloku kodu.

A lock lub SyncLock instrukcji znajduje się obiekt jako argument i następuje blok kodu, który ma zostać wykonana przez tylko jeden wątek na raz.Na przykład:

Public Class TestThreading
    Dim lockThis As New Object 

    Public Sub Process()
        SyncLock lockThis
            ' Access thread-sensitive resources. 
        End SyncLock 
    End Sub 
End Class
public class TestThreading
{
    private System.Object lockThis = new System.Object();

    public void Process()
    {

        lock (lockThis)
        {
            // Access thread-sensitive resources.
        }
    }

}

Argument przekazany lock słowa kluczowego musi być obiekt, na podstawie typu odniesienia i jest używany do definiowania zakresu blokowania.W powyższym przykładzie zakres lock jest ograniczony do tej funkcji, ponieważ żadne odwołania do obiektu lockThis istnieje poza funkcją.Jeśli istniał odniesienie, zablokuj zakres byłoby rozszerzenie do tego obiektu.Ściśle mówiąc obiektu, pod warunkiem jest używany wyłącznie do unikatowej identyfikacji zasobu, które są współużytkowane przez wiele wątków, więc może być wystąpieniem klasy dowolnego.Jednak w praktyce, ten obiekt reprezentuje zwykle zasobu, który wątek konieczne jest synchronizacja.Na przykład jeśli obiekt kontenera ma być używany przez wiele wątków, następnie kontenera mogą być przekazywane do blokowania, i blok kodu zsynchronizowane, blokada po byłoby dostęp kontenera.Tak długo, jak inne wątki blokuje na tym samym zawierają przed uzyskaniem dostępu do niej, a następnie dostęp do obiektu jest bezpiecznie zsynchronizowane.

Ogólnie uniknąć blokowania na najlepiej jest public typu, lub na wystąpienia obiektów poza kontrolą aplikacji.Na przykład lock(this) może być problematyczne, jeśli instancja jest możliwy publicznie, ponieważ kod poza kontrolą może zablokować jak również do obiektu.To może utworzyć sytuacji zakleszczenia, gdy dwa lub więcej wątków oczekiwania na zwolnienie tego samego obiektu.Blokowanie na typ danych publicznych, w przeciwieństwie do obiektu, może być przyczyną problemów z tego samego powodu.Blokowanie na ciągi jest szczególnie ryzykowne, ponieważ ciągi są internowany przez środowiska common language runtime (CLR).Oznacza to, że istnieje jedno wystąpienie każdy ciąg literału dla całego programu, dokładnie ten sam obiekt reprezentuje literał we wszystkich uruchomionych domen aplikacji na wszystkie wątki.W efekcie blokady umieszczony na ciąg znaków o tej samej zawartości w dowolnym miejscu blokad procesu aplikacji wszystkie wystąpienia ciągu w aplikacji.W efekcie najlepiej się zablokować prywatnym ani chronionym członek, który nie jest internowany.Niektóre klasy dostarczy członkom specjalnie do blokowania.Array Typu, na przykład stanowi SyncRoot.Zapewniają wiele typów kolekcji SyncRoot Członkowskie, jak również.

Aby uzyskać więcej informacji o lock i SyncLock instrukcje, zobacz następujące tematy:

Monitory

Podobnie jak lock i SyncLock słowa kluczowe, monitory zapobiec bloków kodu z jednoczesne wykonywanie przez wiele wątków.Enter Metoda umożliwia tylko jeden wątek przejść do następujących instrukcji; inne wątki są zablokowane do momentu wywołania wątku wykonującego Exit.Jest to podobnie jak przy użyciu lock słowa kluczowego.Na przykład:

SyncLock x
    DoSomething()
End SyncLock
lock (x)
{
    DoSomething();
}

Jest to równoważne:

Dim obj As Object = CType(x, Object)
System.Threading.Monitor.Enter(obj)
Try
    DoSomething()
Finally
    System.Threading.Monitor.Exit(obj)
End Try
System.Object obj = (System.Object)x;
System.Threading.Monitor.Enter(obj);
try
{
    DoSomething();
}
finally
{
    System.Threading.Monitor.Exit(obj);
}

Za pomocą lock (C#) lub SyncLock słowa kluczowego (Visual Basic) jest zasadniczo preferowane za pomocą Monitor bezpośrednio, klasy, zarówno ponieważ lock lub SyncLock jest bardziej zwięzły i ponieważ lock lub SyncLock już zwolnieniu monitora podstawowego, nawet jeśli chronione kod generuje wyjątek.Można to osiągnąć, z finally słowa kluczowego, które wykonuje jego blok kodu skojarzone, niezależnie od tego, czy jest wyjątek.

Zdarzenia synchronizacji i uchwyty oczekiwania

Za pomocą lock lub monitor jest przydatne do uniemożliwia jednoczesne wykonywanie wątku wrażliwe bloki kodu, ale konstrukcje te nie pozwalają na jeden wątek, aby komunikować się zdarzenia do innego.Wymaga to zdarzenia synchronizacji, które są obiekty, które mają jeden z dwóch Państw zasygnalizowane i un-signaled, który może służyć do aktywacji i zawieszenia wątków.Wątki mogą zostać zawieszone przez dokonywana oczekiwania na zdarzenia synchronizacji, który jest unsignaled i może być uaktywniona przez zmianę stanu zdarzenia do zasygnalizowane.Jeśli wątek próbuje oczekiwać na zdarzenie zostanie już zasygnalizowane, wątek kontynuuje wykonywanie bezzwłocznie.

Istnieją dwa rodzaje synchronizacji zdarzenia: AutoResetEvent, i ManualResetEvent.Różnią się one w tym AutoResetEvent zmiany z zasygnalizowane do unsignaled automatycznie ilekroć go uaktywnia wątku.Odwrotnie ManualResetEvent pozwala na dowolną liczbę wątków, które ma zostać uaktywniona przez jego stan zasygnalizowany i tylko powróci do unsignaled Państwo, kiedy jego Reset wywoływana jest metoda.

Wątki mogą dokonywane oczekiwania na zdarzenia przez wywołania jednej z metod oczekiwania, takich jak WaitOne, WaitAny, lub WaitAll.WaitHandle.WaitOnepowoduje, że wątek i poczekaj, aż zostanie zasygnalizowany pojedynczego zdarzenia, WaitHandle.WaitAny blokuje wątku, dopóki jeden lub więcej wskazane zdarzenia zostaną zasygnalizowane, i WaitHandle.WaitAll blokuje wątku, dopóki wszystkie wskazane zdarzenia zostaną zasygnalizowane.Zdarzenie zostanie zasygnalizowany po jego Set wywoływana jest metoda.

W poniższym przykładzie, wątek utworzone i uruchomione przez Main funkcji.Nowy wątek oczekuje na zdarzenie przy użyciu WaitOne metody.Wątek jest zawieszone, dopóki zdarzenie staje się sygnalizowane przez wątek główny, który jest wykonywany Main funkcji.Gdy zdarzenie zostanie zasygnalizowany, wątek pomocniczy zwraca.W tym przypadku ponieważ zdarzenie jest używany tylko jeden wątek aktywacji, albo AutoResetEvent lub ManualResetEvent klasy mogą być używane.

Imports System.Threading

Module Module1
    Dim autoEvent As AutoResetEvent

    Sub DoWork()
        Console.WriteLine("   worker thread started, now waiting on event...")
        autoEvent.WaitOne()
        Console.WriteLine("   worker thread reactivated, now exiting...")
    End Sub 

    Sub Main()
        autoEvent = New AutoResetEvent(False)

        Console.WriteLine("main thread starting worker thread...")
        Dim t As New Thread(AddressOf DoWork)
        t.Start()

        Console.WriteLine("main thread sleeping for 1 second...")
        Thread.Sleep(1000)

        Console.WriteLine("main thread signaling worker thread...")
        autoEvent.Set()
    End Sub 
End Module
using System;
using System.Threading;

class ThreadingExample
{
    static AutoResetEvent autoEvent;

    static void DoWork()
    {
        Console.WriteLine("   worker thread started, now waiting on event...");
        autoEvent.WaitOne();
        Console.WriteLine("   worker thread reactivated, now exiting...");
    }

    static void Main()
    {
        autoEvent = new AutoResetEvent(false);

        Console.WriteLine("main thread starting worker thread...");
        Thread t = new Thread(DoWork);
        t.Start();

        Console.WriteLine("main thread sleeping for 1 second...");
        Thread.Sleep(1000);

        Console.WriteLine("main thread signaling worker thread...");
        autoEvent.Set();
    }
}

Obiekt mutex

A obiektu mutex jest podobna do monitora; uniemożliwia jednoczesne wykonywanie bloku kodu przez więcej niż jeden wątek na raz.W rzeczywistości nazwa "mutex" jest skrócona forma termin "wykluczających." W przeciwieństwie do monitorów jednak mutex może służyć do synchronizowania wątków w procesach.Mutex jest reprezentowana przez Mutex klasy.

Gdy używane do synchronizacji między procesami, nosi nazwę obiektu mutex o nazwie obiektu mutex , ponieważ ma być używany w innej aplikacji i dlatego nie może być współużytkowana z zastosowaniem zmiennych globalnych lub statycznych.Powinna mieć nazwę tak, aby obie aplikacje mogą uzyskiwać dostęp do tego samego obiektu mutex.

Chociaż można użyć obiektu mutex wewnątrzprocesowej wątku do synchronizacji, przy użyciu Monitor zwykle jest zalecane, ponieważ monitory zostały zaprojektowane specjalnie dla.NET Framework i dlatego lepiej wykorzystywać zasoby.Z drugiej strony Mutex klasy jest otoki dla konstrukcji Win32.Chociaż jest bardziej wydajne niż monitor, obiektu mutex wymaga współdziałania przejścia, które są bardziej obliczeniowo kosztowna niż te, które są wymagane przez Monitor klasy.Na przykład za pomocą obiektu mutex, zobacz Muteksy.

Klasa blokujących

Można użyć metod Interlocked klasy, aby zapobiec problemom, które mogą wystąpić podczas wiele wątków próbuje jednocześnie zaktualizować lub porównać tę samą wartość.Metody tej klasy umożliwiają bezpieczne przyrostu, zmniejszyć, wymiany i porównywania wartości z dowolnym wątku.

Blokady ReaderWriter

W niektórych przypadkach można zablokować zasobów tylko wtedy, gdy dane są zapisywane i umożliwić wielu klientów jednocześnie odczytać danych, gdy dane, nie są aktualizowane.ReaderWriterLock Klasy wymusza wyłączny dostęp do zasobu, podczas gdy wątek jest modyfikacja zasobów, ale umożliwia dostęp do niewyłącznej, podczas czytania zasobu.Blokady ReaderWriter są użyteczną alternatywą dla wyłącznych blokad, które powodują inne wątki oczekiwania, nawet gdy te wątki nie trzeba aktualizować dane.

Zakleszczenia

Synchronizacji wątków jest Nieoceniony w aplikacjach wielowątkowych, ale zawsze istnieje niebezpieczeństwo tworzenie deadlock, gdzie wiele wątków oczekujących dla siebie i aplikacji pochodzi zatrzymania.Zakleszczenie jest analogiczne do sytuacji, w której samochody są zatrzymywane na stop czterokierunkową i każda osoba jest oczekiwanie na inne przejść.Uniknięcie zakleszczenia jest ważny; Ten klucz jest starannego planowania.Można często przewidywanie zakleszczeń, przez tworzenie diagramu aplikacji wielowątkowych, przed rozpoczęciem kodowania.

Sekcje pokrewne

Porady: korzystanie z puli wątków (C# i Visual Basic)

JAK: Synchronizowanie dostęp do zasobu udostępnionego w środowisku wielowątkowość przy użyciu programu Visual C#.NET

JAK: Tworzenie wątku przy użyciu programu Visual C#.NET

JAK: Prześlij element roboczy puli wątków, przy użyciu programu Visual C#.NET

JAK: Synchronizowanie dostęp do zasobu udostępnionego w środowisku wielowątkowość przy użyciu programu Visual C#.NET

Zobacz też

Informacje

SyncLock — Instrukcja

lock — Instrukcja (odwołanie w C#)

Thread

WaitOne

WaitAny

WaitAll

Join

Start

Sleep

Monitor

Mutex

AutoResetEvent

ManualResetEvent

Interlocked

WaitHandle

EventWaitHandle

System.Threading

Set

Koncepcje

Aplikacje wielowątkowe (C# i Visual Basic)

Muteksy

Monitory

Operacje blokowane

AutoResetEvent

Synchronizowanie danych na potrzeby wielowątkowości

Inne zasoby

Wykonawcze CLR asynchronicznego Model programowania

uproszczony APM z C#

monitor zakleszczenia

Wielowątkowość w składnikach

HOW TO: Synchronize Access to a Shared Resource in a Multithreading Environment by Przy użyciu programu Visual C#.NET