Frage

Ich habe die Dokumentation zu diesem Thema gelesen, und ich glaube, ich verstehe. Eine AutoResetEvent wird zurückgesetzt, wenn der Code durch event.WaitOne() geht, aber ein ManualResetEvent nicht.

Ist das richtig?

War es hilfreich?

Lösung

Ja. Es ist wie der Unterschied zwischen einer Mautstelle und einer Tür. Die ManualResetEvent ist die Tür, die geschlossen werden muss (Reset) manuell. Die AutoResetEvent ist eine Mautstelle, so dass ein Auto durch zu gehen und automatisch zu schließen, bevor die nächsten durchkommen kann.

Andere Tipps

Man stelle sich vor, dass die AutoResetEvent WaitOne() und Reset() als eine einzige atomare Operation ausgeführt wird.

Die kurze Antwort ist ja. Der wichtigste Unterschied ist, dass ein Autoreset nur ein Thread einzelne Warte erlaubt fortzusetzen. Ein Manual auf der anderen Seite halten Threads ermöglicht, mehrere zugleich auch, fortzusetzen, bis Sie es sagen zu stoppen (es Reset).

  

Genommen von C # 3.0 Nutshell Buch, das von   Joseph Albahari

Threading in C # - Gratis E-Book

A Manual ist eine Variante Autoreset. Sie unterscheidet sich darin, dass er nicht automatisch zurückgesetzt, nachdem ein Thread auf einem WaitOne Anruf wird durchgelassen, und so Funktionen wie ein Tor: Aufruf Set öffnet das Tor, so dass eine beliebige Anzahl von Threads, die WaitOne am Tor durch; Aufruf Zurücksetzen das Tor schließt, wodurch möglicherweise auch eine Warteschlange von Kellnern bis zu seinem nächsten geöffnet zu akkumulieren.

Man könnte diese Funktionalität mit einem boolean „gateOpen“ Feld simuliert (mit dem flüchtigen Schlüsselwort deklarierte) in Kombination mit „Spin-Schlaf.“ - immer wieder die Flagge überprüft, und dann für kurze Zeit schlafen

ManualResetEvents werden manchmal verwendet, um zu signalisieren, dass eine bestimmte Operation abgeschlossen ist, oder dass ein abgeschlossene Initialisierung des Threads und bereit ist, Arbeit zu verrichten.

ich einfache Beispiele erstellt Verständnis von ManualResetEvent vs AutoResetEvent zu klären.

AutoResetEvent: Damit können Sie 3 Arbeiter-Thread annehmen müssen. Wenn eines dieser Themen nennen WaitOne() alle anderen 2 Threads wird die Ausführung stoppen und für das Signal warten. Ich gehe davon aus sie verwenden WaitOne(). Es ist wie; wenn ich nicht arbeiten, niemand arbeitet. Im ersten Beispiel können Sie sehen, dass

autoReset.Set();
Thread.Sleep(1000);
autoReset.Set();

Wenn Sie Set() alle Threads aufrufen funktionieren wird und für das Signal warten. Nach 1 Sekunde ich sende zweites Signal und sie ausführen und warten (WaitOne()). Denken Sie über diese Jungs sind Fußballspieler und wenn ein Spieler sagt, ich werde warten, bis Manager ruft mich an, und andere werden warten, bis Manager ihnen sagt, um fortzufahren (Set())

public class AutoResetEventSample
{
    private AutoResetEvent autoReset = new AutoResetEvent(false);

    public void RunAll()
    {
        new Thread(Worker1).Start();
        new Thread(Worker2).Start();
        new Thread(Worker3).Start();
        autoReset.Set();
        Thread.Sleep(1000);
        autoReset.Set();
        Console.WriteLine("Main thread reached to end.");
    }

    public void Worker1()
    {
        Console.WriteLine("Entered in worker 1");
        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker1 is running {0}", i);
            Thread.Sleep(2000);
            autoReset.WaitOne();
        }
    }
    public void Worker2()
    {
        Console.WriteLine("Entered in worker 2");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker2 is running {0}", i);
            Thread.Sleep(2000);
            autoReset.WaitOne();
        }
    }
    public void Worker3()
    {
        Console.WriteLine("Entered in worker 3");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker3 is running {0}", i);
            Thread.Sleep(2000);
            autoReset.WaitOne();
        }
    }
}

In diesem Beispiel man deutlich sehen, dass, wenn Sie zuerst Set() traf es lassen alle Themen gehen, dann nach 1 Sekunde signalisiert alle Threads zu warten! Sobald Sie sie wieder gesetzt, unabhängig sie WaitOne() innen fordern, werden sie am Laufen halten, weil Sie manuell Reset() haben rufen sie alle zu stoppen.

manualReset.Set();
Thread.Sleep(1000);
manualReset.Reset();
Console.WriteLine("Press to release all threads.");
Console.ReadLine();
manualReset.Set();

Es ist mehr über Schiedsrichter / Spieler Beziehung gibt, unabhängig von irgendwelchen der Spieler verletzt ist und warten, dass andere spielen wird weiterhin funktionieren. Wenn Schiedsrichter sagen warten (Reset()) dann alle Spieler bis zum nächsten Signal warten.

public class ManualResetEventSample
{
    private ManualResetEvent manualReset = new ManualResetEvent(false);

    public void RunAll()
    {
        new Thread(Worker1).Start();
        new Thread(Worker2).Start();
        new Thread(Worker3).Start();
        manualReset.Set();
        Thread.Sleep(1000);
        manualReset.Reset();
        Console.WriteLine("Press to release all threads.");
        Console.ReadLine();
        manualReset.Set();
        Console.WriteLine("Main thread reached to end.");
    }

    public void Worker1()
    {
        Console.WriteLine("Entered in worker 1");
        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker1 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
    public void Worker2()
    {
        Console.WriteLine("Entered in worker 2");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker2 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
    public void Worker3()
    {
        Console.WriteLine("Entered in worker 3");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker3 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
}

autoResetEvent.WaitOne()

ist ähnlich

try
{
   manualResetEvent.WaitOne();
}
finally
{
   manualResetEvent.Reset();
}

als eine atomare Operation

OK, in der Regel ist es nicht eine gute Praxis, 2 Antworten in demselben Thread hinzufügen, aber ich wollte nicht meine Antwort bearbeiten / löschen, da es auf eine andere Weise helfen können.

Nun, ich erstellt, viel umfassender und leicht zu verstehen, führen zu erlernende Konsole app Schnipsel unten.

Führen Sie einfach die Beispiele auf zwei verschiedene Konsolen und Verhalten beobachten. Sie werden viel mehr klare Vorstellung gibt, was hinter den Kulissen passiert.

Manual Reset-Ereignis

using System;
using System.Threading;

namespace ConsoleApplicationDotNetBasics.ThreadingExamples
{
    public class ManualResetEventSample
    {
        private readonly ManualResetEvent _manualReset = new ManualResetEvent(false);

        public void RunAll()
        {
            new Thread(Worker1).Start();
            new Thread(Worker2).Start();
            new Thread(Worker3).Start();
            Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below.");
            Thread.Sleep(15000);
            Console.WriteLine("1- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("2- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("3- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("4- Main will call ManualResetEvent.Reset() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Reset();
            Thread.Sleep(2000);
            Console.WriteLine("It ran one more time. Why? Even Reset Sets the state of the event to nonsignaled (false), causing threads to block, this will initial the state, and threads will run again until they WaitOne().");
            Thread.Sleep(10000);
            Console.WriteLine();
            Console.WriteLine("This will go so on. Everytime you call Set(), ManualResetEvent will let ALL threads to run. So if you want synchronization between them, consider using AutoReset event, or simply user TPL (Task Parallel Library).");
            Thread.Sleep(5000);
            Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);

        }

        public void Worker1()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker1 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker2()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker2 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker3()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker3 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
    }

}

 Manual Reset Ereignisausgang

Auto-Reset-Ereignis

using System;
using System.Threading;

namespace ConsoleApplicationDotNetBasics.ThreadingExamples
{
    public class AutoResetEventSample
    {
        private readonly AutoResetEvent _autoReset = new AutoResetEvent(false);

        public void RunAll()
        {
            new Thread(Worker1).Start();
            new Thread(Worker2).Start();
            new Thread(Worker3).Start();
            Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below.");
            Thread.Sleep(15000);
            Console.WriteLine("1- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("2- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("3- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("4- Main will call AutoResetEvent.Reset() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Reset();
            Thread.Sleep(2000);
            Console.WriteLine("Nothing happened. Why? Becasuse Reset Sets the state of the event to nonsignaled, causing threads to block. Since they are already blocked, it will not affect anything.");
            Thread.Sleep(10000);
            Console.WriteLine("This will go so on. Everytime you call Set(), AutoResetEvent will let another thread to run. It will make it automatically, so you do not need to worry about thread running order, unless you want it manually!");
            Thread.Sleep(5000);
            Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);

        }

        public void Worker1()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker1 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker2()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker2 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker3()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker3 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
    }

}

 Auto-Reset Ereignisausgang

Ja. Das ist absolut richtig.

Sie konnte sehen, Manual als Weg Zustand anzuzeigen. Etwas ist (Set) oder aus (Reset). Ein Ereignis mit einer gewissen Dauer. Alle für diesen Zustand warten Thread passieren kann gehen.

Ein Autoreset ist vergleichbar mit einem Signal. Ein Ein Schuss Hinweis darauf, dass etwas passiert ist. Ein Auftreten ohne Dauer. Typischerweise, aber nicht unbedingt die „Etwas“, das geschehen ist, ist klein und muss von einem einzigen Thread behandelt werden - daher die automatische Rückstellung nach einem einzigen Thread das Ereignis verbraucht hat.

Ja, das ist richtig.

Sie können eine Idee durch die Nutzung dieser beiden erhalten.

Wenn Sie sagen, dass Sie mit einigen der Arbeit und andere (Themen) fertig sind darauf gewartet können nun damit fortfahren, sollten Sie Manual verwenden.

Wenn Sie die gegenseitigen exklusiven Zugriff auf jede Ressource haben müssen, sollten Sie Autoreset verwenden.

Autoreset hält eine boolean Variable im Speicher. Wenn die Boolesche Variable falsch ist dann blockiert er den Faden, und wenn die Boolesche Variable wahr ist deblockiert es den Faden.

Wenn wir ein Objekt instanziiert Autoreset, übergeben wir den Standardwert von Booleschen Wert im Konstruktor. Im Folgenden ist die Syntax ein Autoreset Objekt von instanziiert.

AutoResetEvent autoResetEvent = new AutoResetEvent(false);

WaitOne Methode

Diese Methode blockiert den aktuellen Thread und für das Signal von anderen Thread warten. WaitOne Verfahren setzt den aktuellen Thread in einen Sleep-Thread-Zustand. WaitOne Methode gibt true zurück, wenn es das Signal empfängt, sonst false zurück.

autoResetEvent.WaitOne();

Zweite Überlastung der WaitOne Methode für die angegebene Anzahl von Sekunden warten. Wenn es kein Signal Thread weiter bekommt seine Arbeit.

static void ThreadMethod()
{
    while(!autoResetEvent.WaitOne(TimeSpan.FromSeconds(2)))
    {
        Console.WriteLine("Continue");
        Thread.Sleep(TimeSpan.FromSeconds(1));
    }

    Console.WriteLine("Thread got signal");
}

Wir nannten WaitOne Verfahren durch die 2 Sekunden als Argumente übergeben. In der while-Schleife, ist es für das Signal wartet 2 Sekunden dann er seine Arbeit fortsetzt. Wenn der Faden das Signal WaitOne gibt true zurück bekam und verlässt die Schleife und druckt das „Thread bekam Signal“.

Methode

Autoreset Set Methode das Signal an den wartenden Thread geschickt seine Arbeit fortzusetzen. Im Folgenden ist die Syntax Set Methode aufrufen.

autoResetEvent.Set();

Manual hält eine boolean Variable im Speicher. Wenn die Boolesche Variable falsch ist dann blockiert sie alle Threads und wenn die Boolesche Variable wahr ist deblockiert es alle Themen.

Wenn wir einen Manual instanziiert, initialisiert werden wir es mit dem Standard Booleschen Wert.

ManualResetEvent manualResetEvent = new ManualResetEvent(false);

In dem obigen Code initialisieren wir den Manual mit falschem Wert, das alle Fäden Einrichtung, die die WaitOne Methode aufruft blockiert, bis ein Thread die Set () Methode aufruft.

Wenn wir Manual mit wahrem Wert zu initialisieren, alle Fäden, die die WaitOne Methode rufen nicht blockieren und frei weiter verfahren ist.

WaitOne Methode

Diese Methode blockiert den aktuellen Thread und für das Signal von anderen Thread warten. Es gibt true zurück, wenn sie empfängt ein Signal sonst false zurück.

Im Folgenden ist die Syntax von WaitOne Methode aufrufen.

manualResetEvent.WaitOne();

In der zweiten Überlast WaitOne Methode können wir das Zeitintervall, bis die aktuellen Thread Warten auf das Signal angeben. Wenn innerhalb der Zeit intern, es nicht ein Signal empfängt, es false zurück und geht in die nächste Zeile der Methode.

Im Folgenden ist die Syntax von WaitOne Methode mit Zeitintervall aufgerufen wird.

bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));

Wir geben haben 5 Sekunden in die WaitOne Methode. Wenn das Objekt Manual kein Signal zwischen 5 Sekunden empfängt, stellen Sie die isSignalled Variable auf false gesetzt.

Set-Methode

Diese Methode wird für das Senden des Signals an alle wartenden Threads verwendet. Set () Methode setzen die Manual Boolesche Variable auf true Objekt. Alle wartenden Threads, entblockt werden und gehen weiter.

Im Folgenden ist die Syntax des Aufrufs Set () -Methode.

manualResetEvent.Set();

Reset-Methode

Sobald wir die Set () -Methode auf dem Manual Objekt aufrufen, bleibt seine boolean true. Um den Wert zurücksetzen können wir Reset () Methode verwenden. Reset-Methode des Booleschen Wert auf false ändern.

Im Folgenden finden Sie die Syntax der Reset-Methode aufrufen.

manualResetEvent.Reset();

Wir müssen sofort anrufen Methode Zurücksetzen nach dem Aufruf von Set-Methode, wenn wir Signal an Threads mehrmals senden möchten.

Wenn Sie Autoreset und Manual zu verstehen, müssen Sie nicht verstehen Threading aber Interrupts!

.NET will Low-Level-Programmierung der entfernteste möglich heraufbeschwören.

Eine Interrupts ist etwas in Low-Level-Programmierung verwendet, die auf ein Signal gleich dem von niedrig hoch wurde (oder umgekehrt). Wenn dies das Programm geschieht unterbricht seine normale Ausführung und die Ausführung Zeiger auf die Funktion verschieben, die dieses Griffe Ereignis .

Das erste, was zu tun ist, wenn ein Interrupt happend ist auf Zurücksetzen seinen Zustand, becosa die Hardware auf diese Weise funktioniert:

  1. wird ein Stift auf ein Signal und die Hardware angeschlossen anhören, sie zu ändern (das Signal nur zwei Zustände haben könnte).
  2. , wenn sich das Signal bedeutet, dass etwas passiert und die Hardware einen Speichervariable setzen , um den Zustand passiert (und es wie diese, auch wenn die Signaländerung bleiben wieder).
  3. das Programm feststellen, dass variable Änderungszustände und die Ausführung einer Bearbeitungsfunktion bewegen.
  4. hier das erste, was zu tun ist, um die Lage sein, wieder dieses Interrupt zu hören, ist auf Zurücksetzen diese Speichervariablen in den Zustand nicht-passiert ist.

Das ist der Unterschied zwischen Manual und Autoreset.
Wenn ein Manual passieren und ich setze es nicht, das nächste Mal passiert es mir nicht in der Lage sein, es zu hören.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top