Der richtige Weg Monitor.Wait
und Monitor.Pulse
/PulseAll
ist nicht so über ein Instrument des Wartens zu sehen, sondern (für Wait
) als ein Mittel, das System wissen zu lassen, dass der Code in einer Warteschleife ist, die nicht Ausfahrt bis sich etwas von Interesse ändert, und (für Pulse
/PulseAll
) als ein Mittel, das System wissen zu lassen, dass Code gerade etwas geändert hat, das die Ausgangsbedingung erfüllen könnte, die Warteschleife eines anderen Threads. Man sollte in der Lage sein, alle Vorkommen von Wait
durch Sleep(0)
zu ersetzen, und Code funktioniert immer noch korrekt (auch wenn es viel weniger effizient ist, da die CPU-Zeit wiederholt Bedingungen ausgibt, die sich nicht geändert haben).
Für diesen Mechanismus zu arbeiten, ist es notwendig, die Möglichkeit der folgenden Sequenz zu vermeiden:
Der Code in der Warteschleife testet die Bedingung, wenn es nicht erfüllt ist.
Der Code in einem anderen Thread ändert die Bedingung so, dass sie erfüllt ist.
Der Code in diesem anderen Thread pulsiert die Sperre (auf die noch niemand wartet).
Der Code in der Warteschleife führt einen Wait
aus, da seine Bedingung nicht erfüllt wurde.
Die Wait
Methode erfordert, dass die Warte Thread eine Sperre haben, da dies der einzige Weg ist, kann es sicher sein, dass die Bedingung, es auf wartet nicht zwischen der Zeit verändern sie getestet hat und die Zeit der Code das führt Wait
. Die Pulse
Methode erfordert eine Sperre, da dies die einzige Möglichkeit ist, sicher zu sein, dass, wenn ein anderer Thread sich zur Ausführung einer Wait
"committed", die Pulse
nicht auftreten wird, bis der andere Thread dies tatsächlich tut. Beachten Sie, dass die Verwendung von Wait
innerhalb eines Schlosses nicht garantiert, dass es korrekt verwendet wird, aber es gibt keine Möglichkeit, dass die Verwendung von Wait
außerhalb einer Sperre möglicherweise korrekt ist.
Der Entwurf Wait
/Pulse
funktioniert tatsächlich einigermaßen gut, wenn beide Seiten zusammenarbeiten. Die größten Schwächen des Designs, IMHO, sind (1) es gibt keinen Mechanismus für einen Thread, um zu warten, bis einer von einer Anzahl von Objekten gepulst ist; (2) selbst wenn man ein Objekt "herunterfährt", so dass alle zukünftigen Warteschleifen sofort beendet werden sollten (wahrscheinlich durch Überprüfen eines Exit-Flags), kann nur sichergestellt werden, dass Wait
, an die sich ein Thread gebunden hat, eine Pulse
erhält ist, das Schloss zu erwerben, möglicherweise auf unbestimmte Zeit darauf wartend, dass es verfügbar wird.
warum bevorzugen Sie es? Wie würdest du den Monitor synchronisieren, nur eine Sperre für das Locker-Objekt, das für den Monitor verwendet wird? Wird durch die Sperre keine weitere Kontextumschaltung hinzugefügt, die ResetEvents nicht benötigt? – user437631
@ user437631: Ja, nur eine normale 'lock' Anweisung ist in Ordnung. Das kann einen zusätzlichen Kontextwechsel erfordern oder nicht - und ich denke nicht, dass Sie irgendwelche Beweise dafür haben, dass ResetEvents dies nicht benötigen würde. Da es sich um CLR-interne Objekte und nicht um prozessübergreifende Win32-Objekte handelt, sind Monitore leichter als ResetEvents. –