Ich habe die Dokumentation dazu gelesen und glaube, dass ich es verstanden habe. Eine AutoResetEvent
wird zurückgesetzt, wenn der Code durchläuft event.WaitOne()
sondern ein ManualResetEvent
nicht.
Ist dies richtig?
Ich habe die Dokumentation dazu gelesen und glaube, dass ich es verstanden habe. Eine AutoResetEvent
wird zurückgesetzt, wenn der Code durchläuft event.WaitOne()
sondern ein ManualResetEvent
nicht.
Ist dies richtig?
OK, normalerweise ist es keine gute Praxis, 2 Antworten im selben Thread hinzuzufügen, aber ich wollte meine vorherige Antwort nicht bearbeiten/löschen, da sie auf andere Weise helfen kann.
Jetzt habe ich einen viel umfangreicheren und leicht verständlichen Ausschnitt aus der Konsolenanwendung zum Ausführen und Lernen erstellt.
Lassen Sie die Beispiele einfach auf zwei verschiedenen Konsolen laufen und beobachten Sie das Verhalten. Sie werden dort eine viel klarere Vorstellung davon bekommen, was hinter den Kulissen passiert.
Manueller 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);
}
}
}
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);
}
}
}
AutoResetEvent verwaltet eine boolesche Variable im Speicher. Wenn die boolesche Variable false ist, wird der Thread blockiert, und wenn die boolesche Variable true ist, wird der Thread freigegeben.
Wenn wir ein AutoResetEvent-Objekt instanziieren, übergeben wir im Konstruktor den Standardwert boolean value. Im Folgenden wird die Syntax für die Instanziierung eines AutoResetEvent-Objekts beschrieben.
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
WaitOne-Methode
Diese Methode blockiert den aktuellen Thread und wartet auf das Signal des anderen Threads. Die WaitOne-Methode versetzt den aktuellen Thread in einen Sleep-Thread-Zustand. Die WaitOne-Methode gibt true zurück, wenn sie das Signal empfängt, andernfalls gibt sie false zurück.
autoResetEvent.WaitOne();
Zweite Überladung der WaitOne-Methode wartet auf die angegebene Anzahl von Sekunden. Wenn er kein Signal erhält, setzt der Thread seine Arbeit fort.
static void ThreadMethod()
{
while(!autoResetEvent.WaitOne(TimeSpan.FromSeconds(2)))
{
Console.WriteLine("Continue");
Thread.Sleep(TimeSpan.FromSeconds(1));
}
Console.WriteLine("Thread got signal");
}
Wir rufen die Methode WaitOne auf, indem wir die 2 Sekunden als Argumente übergeben. In der while-Schleife wird 2 Sekunden lang auf das Signal gewartet, dann wird die Arbeit fortgesetzt. Wenn der Thread das Signal erhalten hat, gibt WaitOne den Wert true zurück, verlässt die Schleife und druckt die Meldung "Thread got signal".
Methode einstellen
Die Methode AutoResetEvent Set sendet das Signal an den wartenden Thread, um seine Arbeit fortzusetzen. Nachfolgend ist die Syntax für den Aufruf der Methode Set dargestellt.
autoResetEvent.Set();
ManualResetEvent verwaltet eine boolesche Variable im Speicher. Wenn die boolesche Variable false ist, werden alle Threads blockiert, und wenn die boolesche Variable true ist, werden alle Threads freigegeben.
Wenn wir ein ManualResetEvent instanziieren, initialisieren wir es mit einem booleschen Standardwert.
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
Im obigen Code initialisieren wir das ManualResetEvent mit dem Wert false, d.h. alle Threads, die die WaitOne-Methode aufrufen, blockieren, bis ein Thread die Set()-Methode aufruft.
Wenn wir ManualResetEvent mit dem Wert true initialisieren, werden alle Threads, die die WaitOne-Methode aufrufen, nicht blockiert und sind frei, um weiterzumachen.
WaitOne-Methode
Diese Methode blockiert den aktuellen Thread und wartet auf das Signal des anderen Threads. Sie gibt true zurück, wenn sie ein Signal erhält, sonst false.
Nachfolgend ist die Syntax für den Aufruf der WaitOne-Methode aufgeführt.
manualResetEvent.WaitOne();
In der zweiten Überladung der WaitOne-Methode können wir das Zeitintervall angeben, bis der aktuelle Thread auf das Signal wartet. Wenn innerhalb der internen Zeit kein Signal empfangen wird, wird false zurückgegeben und die nächste Zeile der Methode aufgerufen.
Nachfolgend ist die Syntax für den Aufruf der Methode WaitOne mit Zeitintervall dargestellt.
bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));
Wir haben 5 Sekunden in der WaitOne-Methode angegeben. Wenn das Objekt manualResetEvent innerhalb von 5 Sekunden kein Signal empfängt, setzt es die Variable isSignalled auf false.
Methode einstellen
Diese Methode wird verwendet, um das Signal an alle wartenden Threads zu senden. Set() Die Methode setzt die boolesche Variable des ManualResetEvent-Objekts auf true. Alle wartenden Threads werden entsperrt und können weiterarbeiten.
Nachfolgend ist die Syntax für den Aufruf der Methode Set() aufgeführt.
manualResetEvent.Set();
Reset-Methode
Sobald wir die Set()-Methode für das ManualResetEvent-Objekt aufrufen, bleibt sein Boolescher Wert wahr. Um den Wert zurückzusetzen, können wir die Methode Reset() verwenden. Die Reset-Methode ändert den booleschen Wert in false.
Im Folgenden finden Sie die Syntax für den Aufruf der Methode Reset.
manualResetEvent.Reset();
Wir müssen die Reset-Methode sofort nach dem Aufruf der Set-Methode aufrufen, wenn wir das Signal mehrmals an Threads senden wollen.
Ja, das ist absolut richtig.
Man könnte ManualResetEvent als eine Möglichkeit sehen, den Zustand anzuzeigen. Etwas ist eingeschaltet (Set) oder ausgeschaltet (Reset). Ein Ereignis mit einer gewissen Dauer. Jeder Thread, der auf diesen Zustand wartet, kann fortfahren.
Ein AutoResetEvent ist eher mit einem Signal vergleichbar. Ein einmaliger Hinweis darauf, dass etwas passiert ist. Ein Ereignis ohne jegliche Dauer. Typischerweise, aber nicht notwendigerweise, ist das "Etwas", das passiert ist, klein und muss von einem einzigen Thread verarbeitet werden - daher die automatische Rücksetzung, nachdem ein einzelner Thread das Ereignis konsumiert hat.
Ja, das ist richtig.
Sie können sich anhand der Verwendung dieser beiden Begriffe ein Bild machen.
Wenn Sie mitteilen müssen, dass Sie mit einer Arbeit fertig sind und andere (Threads), die darauf warten, nun fortfahren können, sollten Sie ManualResetEvent verwenden.
Wenn Sie einen gegenseitigen exklusiven Zugriff auf eine Ressource benötigen, sollten Sie AutoResetEvent verwenden.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.