[C#-Grundlagen] Leicht verständliches AutoResetEvent und ManualResetEvent

Gründliches Verständnis von AutoResetEvent

AutoResetEvent ist ein Thread-Synchronisierungsprimitiv, das zum Koordinieren der Ausführungsreihenfolge von Threads in einer Multithread-Umgebung verwendet wird. Es handelt sich um einen von .NET Framework bereitgestellten Synchronisierungsmechanismus für die Kommunikation und Zusammenarbeit zwischen Threads.

AutoResetEvent verwaltet ein Statusflag, das einen von zwei Zuständen haben kann, signalisiert oder nicht signalisiert. Ein Thread kann seine eigene Ausführung steuern, indem er auf ein Signal wartet oder ein Signal setzt.

AutoResetEvent verfügt über zwei Hauptmethoden: WaitOne und Set. Im Folgenden sind die Funktionen und die Verwendung dieser Methoden aufgeführt:

1. WaitOne:
   – Wenn ein Thread die WaitOne-Methode aufruft, wechselt er in einen Wartezustand, bis ein Signal empfangen wird.
   – Wenn sich das AutoResetEvent im nicht signalisierten Zustand befindet, blockiert die WaitOne-Methode die Ausführung des Threads.
   – Wenn sich das AutoResetEvent im signalisierten Zustand befindet, verbraucht die WaitOne-Methode das Signal und versetzt das AutoResetEvent wieder in den nicht signalisierten Zustand.
   - Sie können die Timeout-Zeit über die überladene Methode von WaitOne angeben. Nach der angegebenen Zeit wird der Thread weiter ausgeführt, ohne auf das Signal zu warten.

2. Set:
   – Wenn ein Thread die Set-Methode aufruft, setzt er den Status des AutoResetEvents auf signalisiert.
   – Wenn ein Thread auf ein Signal wartet, wird er aktiviert und beginnt mit der Ausführung.
   – Wenn keine Threads auf das Signal warten, wird durch den Aufruf der Set-Methode auch der Status des AutoResetEvents auf signalisiert gesetzt, hat aber keine weiteren Auswirkungen.
   – Auch wenn die Set-Methode mehrmals aufgerufen wird, bleibt das AutoResetEvent nur einmal signalisiert, bis es verbraucht wird.

AutoResetEvent funktioniert wie ein Türschloss oder eine Ampel. Ein Thread kann seine eigene Ausführung blockieren, indem er auf das Öffnen des Latches wartet (WaitOne), während andere Threads den wartenden Thread aufwecken können, indem sie den Latch auf Öffnen setzen (Set).

AutoResetEvent ist bei der Multithread-Programmierung sehr nützlich, insbesondere wenn Sie die Ausführungsreihenfolge von Threads steuern oder eine Zusammenarbeit zwischen Threads erreichen müssen. Es bietet eine einfache und effiziente Möglichkeit, die Vorgänge von Threads zu synchronisieren und sicherzustellen, dass Threads in der gewünschten Reihenfolge ausgeführt werden.

 Zum Beispiel

Angenommen, es gibt zwei Threads, ein Thread ist für die Produktion von Artikeln verantwortlich und der andere Thread ist für den Konsum von Artikeln verantwortlich. Diese beiden Threads müssen synchronisiert werden, um sicherzustellen, dass der Verbraucher den Artikel konsumieren kann, nachdem der Produzent ihn produziert hat.

Diese Synchronisierung kann einfach mit AutoResetEvent erreicht werden. Hier ist ein einfacher Beispielcode:

using System;
using System.Threading;

class ProgramesetEvent producerEvent = new AutoResetEvent(false);
    static AutoResetEvent consumerEvent = new AutoResetEvent(true);

    static int item = 0;

    static void Main()
    {
        Thread p
{
    static AutoRonsumerThread = new Thread(ConsumeItems);

        producerroducerThread = new Thread(ProduceItems);
        Thread cThread.Start();
        consumerThread.Start();

        producerThread.Join();
        consumerThread.Join();

        Console.WriteLine("Finished");
    }

    static void ProduceItems()
    {
        for (int i = 0; i < 5; i++)
        {
            consumerEvent.WaitOne(); // 等待消费者消费物品

            // 生产物品
            item = i;
            Console.WriteLine("Produced item: " + item);

            producerEvent.Set(); // 发送信号给消费者
        }
    }

    static void ConsumeItems()
    {
        for (int i = 0; i < 5; i++)
        {
            producerEvent.WaitOne(); // 等待生产者生产物品

            // 消费物品
            Console.WriteLine("Consumed item: " + item);

            consumerEvent.Set(); // 发送信号给生产者
        }
    }
}

In diesem Beispiel gibt es eine gemeinsam genutzte Variable „item“, die den Artikel darstellt, der gerade produziert oder verbraucht wird. „producerEvent“ steuert die Ausführung von Producer-Threads und „consumerEvent“ steuert die Ausführung von Consumer-Threads.

Der Produzenten-Thread wechselt in den Wartezustand, indem er „consumerEvent.WaitOne()“ aufruft, bis der Konsumenten-Thread das Element verbraucht. Anschließend generiert der Producer-Thread ein neues Element, speichert es in der Variablen „item“ und ruft „producerEvent.Set()“ auf, um das Signal an den Consumer-Thread zu senden.

Der Consumer-Thread geht in einen Wartezustand über, indem er „producerEvent.WaitOne()“ aufruft, bis der Producer-Thread Elemente produziert. Dann ruft der Consumer-Thread das Element aus der Variable „item“ ab, konsumiert es und ruft „consumerEvent.Set()“ auf, um ein Signal an den Producer-Thread zu senden.

Auf diese Weise können Produzenten- und Konsumenten-Threads abwechselnd Elemente produzieren und konsumieren und dabei synchron bleiben. Die Verwendung von AutoResetEvent stellt die korrekte sequentielle Ausführung zwischen Produzenten- und Verbraucher-Threads sicher und vermeidet Race Conditions und Dateninkonsistenzen.

Wofür werden die von new AutoResetEvent übergebenen Parameter verwendet?

Der im Konstruktor von AutoResetEvent übergebene Parameter ist ein boolescher Wert, der zur Angabe des anfänglichen Signalzustands verwendet wird. Dieser Parameter heißt „initialState“.

– Wenn „initialState“ „true“ ist, ist der Anfangszustand des AutoResetEvents der signalisierte Zustand. Das heißt, der Thread wird beim Warten nicht blockiert, sondern kann direkt ausgeführt werden. Wenn zu diesem Zeitpunkt die Methode „WaitOne“ aufgerufen wird und sich das AutoResetEvent im nicht signalisierten Zustand befindet, setzt der Thread die Ausführung sofort fort, ohne auf das Signal zu warten.

– Wenn „initialState“ „false“ ist, ist der Anfangszustand des AutoResetEvents der nicht signalisierte Zustand. Das heißt, Threads werden während des Wartens blockiert und können nicht weiter ausgeführt werden, bis ein Signal empfangen wird. Wenn zu diesem Zeitpunkt die Methode „WaitOne“ aufgerufen wird und sich das AutoResetEvent im nicht signalisierten Zustand befindet, wird der Thread blockiert, bis die Methode „Set“ aufgerufen wird, um ihn in den signalisierten Zustand zu versetzen.

Der anfängliche Signalzustand kann entsprechend den tatsächlichen Anforderungen ausgewählt werden. Wenn Sie möchten, dass der Thread weiter ausgeführt wird, ohne zu Beginn blockiert zu werden, können Sie den signalisierten Status verwenden. Wenn Sie möchten, dass der Thread zu Beginn auf die Ausführung des Signals wartet, können Sie den nicht signalisierten Status verwenden.

Beispielsweise kann im Producer-Consumer-Beispiel der nicht signalisierte Zustand als Anfangszustand verwendet werden, um sicherzustellen, dass der Producer-Thread zunächst auf ein Signal vom Consumer-Thread wartet, um mit der Produktion von Elementen zu beginnen. Dies verhindert, dass Hersteller ständig neue Produkte produzieren, wenn keine Verbraucher diese konsumieren.

Was ist der Unterschied zwischen AutoResetEvent und ManualResetEvent?

Sowohl AutoResetEvent als auch ManualResetEvent sind Thread-Synchronisierungsprimitive, die zur Koordinierung der Ausführungsreihenfolge von Threads in einer Multithread-Umgebung verwendet werden. Es gibt jedoch einige wichtige Unterschiede zwischen ihnen.

1. Trigger-Methode:
   - AutoResetEvent: Nach dem Aufruf der Methode „Set“ wird nur ein wartender Thread aufgeweckt und mit der Ausführung fortgefahren. Anschließend kehrt AutoResetEvent automatisch in den Zustand ohne Signal zurück. Das heißt, jeder Aufruf der „Set“-Methode weckt nur einen wartenden Thread.
   - ManualResetEvent: Nach dem Aufruf der „Set“-Methode werden alle wartenden Threads geweckt und werden weiter ausgeführt, bis das ManualResetEvent durch expliziten Aufruf der „Reset“-Methode in den nicht signalisierten Zustand zurückgesetzt wird. Das heißt, jeder Aufruf der „Set“-Methode weckt alle wartenden Threads auf.

2. Status-Reset:
   - AutoResetEvent: Automatisches Zurücksetzen auf den Status „Kein Signal“. Das heißt, wenn ein Thread auf ein Signal wartet und aufgeweckt wird, setzt sich AutoResetEvent automatisch in den Zustand ohne Signal zurück, sodass der nächste wartende Thread weiter warten kann.
   - ManualResetEvent: Erfordert einen expliziten Aufruf der „Reset“-Methode, um sie in den nicht signalisierten Zustand zurückzusetzen. Das heißt, das ManualResetEvent bleibt signalisiert, bis die Methode „Reset“ aufgerufen wird, um es wieder in den nicht signalisierten Zustand zu versetzen.

3. Wartemethode:
   - AutoResetEvent: Wenn sich das AutoResetEvent beim Aufruf der Methode „WaitOne“ im nicht signalisierten Zustand befindet, wird der Thread blockiert, bis das Signal empfangen wird. Wenn das AutoResetEvent signalisiert wird, verbraucht der Thread das Signal und setzt die Ausführung fort.
   - ManualResetEvent: Wenn sich ManualResetEvent beim Aufruf der Methode „WaitOne“ im nicht signalisierten Zustand befindet, wird der Thread blockiert, bis das Signal empfangen wird. Selbst wenn sich ManualResetEvent im signalisierten Zustand befindet, verbraucht der Thread das Signal und setzt die Ausführung fort, ohne ihn automatisch in den nicht signalisierten Zustand zurückzusetzen.

Entsprechend diesen Unterschieden können Sie AutoResetEvent oder ManualResetEvent verwenden, um sich an unterschiedliche Thread-Synchronisierungsanforderungen anzupassen.

- Wenn Sie jeweils nur einen wartenden Thread aufwecken müssen und möchten, dass der Thread nach Empfang eines Signals automatisch in den Zustand ohne Signal zurückgesetzt wird, können Sie AutoResetEvent verwenden. Dies ist für einige Szenarien nützlich, in denen Aufgaben in der Warteschlange stehen.
– Wenn Sie alle wartenden Threads aufwecken müssen und möchten, dass der Thread nach dem Empfang eines Signals so lange signalisiert bleibt, bis er durch expliziten Aufruf der Reset-Methode in den nicht signalisierten Zustand zurückgesetzt wird, können Sie ManualResetEvent verwenden. Dies ist für einige Broadcast-Benachrichtigungsszenarien nützlich.

Je nach Anwendungsszenario und Thread-Synchronisierungsanforderungen muss ausgewählt werden, welches Synchronisierungsprimitiv verwendet werden soll.

Zusammenfassung

Das Prinzip der Signalsynchronisation besteht darin, auf das Signal zu warten, den Signalstatus direkt zu durchlaufen und zu warten, wenn kein Signal vorhanden ist. Worauf wartest du? Durch den Aufruf von WaitOnce usw. Set setzt das Signal auf „Signal“ und „ReSet“ setzt den Zustand auf „Kein Signal“. AutoResetEvent wird nach dem Warten automatisch zu „kein Signal“! Das Gegenteil ist ManualResetEven.

Manuelle Übersetzung ist manuell. Erfordert einen expliziten Aufruf der „Reset“-Methode, um sie in den nicht signalisierten Zustand zurückzusetzen.

Ein weiteres wichtiges Thema ist der Unterschied zwischen mehreren!

Wir können WaitOnce viele Male in verschiedenen Threads über dasselbe AutoResetEvent-Objekt aufrufen.

Auf diese Weise warten viele Threads auf dasselbe Signal. Da AutoResetEvent automatisch kein Signal wiederherstellt, wird nur ein wartender Thread geweckt und mit der Ausführung fortgefahren. Dann muss dieser Thread der erste Ort sein, an dem WaitOnce aufgerufen wird, da WaitOnce einmal aufgerufen und übergeben wurde , AutoResetEvent stellt automatisch kein Signal wieder her. Der Rest muss natürlich warten.

Und ManualResetEven ist manuell, sodass alle aktiviert werden können.

Supongo que te gusta

Origin blog.csdn.net/songhuangong123/article/details/131591253
Recomendado
Clasificación