C#: yield return in lock-Kontext?

1 Antwort

Vom Beitragsersteller als hilfreich ausgezeichnet

Am Code ist nichts falsch, dass was ich dort sehe, macht genau dass was die Exception auswirft.

Schau dir mal genau an wie yield return in C# funktioniert, du benutzt es leider nicht effizient bzw. wie man es eigentlich nutzen sollte;

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/yield

https://learn.microsoft.com/en-us/archive/msdn-magazine/2017/june/essential-net-custom-iterators-with-yield

zum ersten würde ich aync rausnehmen, da du sonst nicht gut debuggen kannst

Bei yield return wird Iterator-State-Machine verwendet, was bedeutet, dass der Code angehalten und später fortgesetzt werden kann. Das führt dazu, dass der lock-Kontext verlassen wird, bevor die Iteration abgeschlossen ist.

Da yield return die Methode beim ersten Auftreten verlässt und später beim Aufruf des nächsten Werts fortgesetzt wird, endet der lock-Block, sobald der erste Wert zurückgegeben wird. Danach wird der Code außerhalb des lock-Blocks fortgesetzt, was bedeutet, dass keine Synchronisierung mehr vorhanden ist, wenn der Rest der Sammlung durchlaufen wird.

meiner Meinung nach führt dass sehr wahrscheinlich zu deiner Exception .

Du kannst die Ergebnisse vor dem Verlassen des lock-Blocks vollständig sammeln und anschließend außerhalb des lock-Blocks zurückgeben. Das vermeidet den yield return-Mechanismus innerhalb des lock-Kontexts.

Wenn du die Enumeration mit yield return trotzdem benutzen willst, wovon ich dir aber abrate, musst du schauen, dass der gesamte Enumerationsprozess innerhalb des lock-Blocks erfolgt. Dies schließt den lock-Block erst nach Abschluss der Iteration

Vom zweiten würde ich aber eher wie gesagt abraten wenn die Iteration lange dauert oder wenn andere Threads ebenfalls auf den lock-Block zugreifen wollen, sonst bekommst du wahrscheinlich andere Probleme.

Woher ich das weiß:Berufserfahrung – Softwareentwickler C#

isohypse 
Beitragsersteller
 13.09.2024, 12:19
Du kannst die Ergebnisse vor dem Verlassen des lock-Blocks vollständig sammeln und anschließend außerhalb des lock-Blocks zurückgeben. Das vermeidet den yield return-Mechanismus innerhalb des lock-Kontexts.

ja, klar. ich will ja nur verstehen, WARUM das passiert, nicht wie ich es behebe.

 endet der lock-Block, sobald der erste Wert zurückgegeben wird. 

Bist du dir sicher? lock ist ja äquivalent zu

    Monitor.Enter(_lockObject);

    try 
	{
		foreach(var e in _myList)
		{
			if (e.x == par)
			{
				  yield return e;
			}
		}
    }
    finally 
	{
      Monitor.Exit(_lockObject);
    }

und da wird erst in finally Block der Lock released.

Hier liest man das auch:

https://stackoverflow.com/questions/2847586/yield-returns-within-lock-statement

zum ersten würde ich aync rausnehmen, da du sonst nicht gut debuggen kannst

Wie meinst du das? Ich MUSS asynchrone Funktionen aufrufen, da komme ich nicht dran vorbei.

Wenn ich in der äußeren Schleife keine asynchronen Methoden aufrufe, dann geht es.

Diese Beobachtung war ja der Grund für meine Idee, dass der Thread nach dem Abarbeiten der asynchronen Methode in einem anderen Thread landet und dies die Exception auslöst.

https://github.com/dotnet/roslyn/issues/46004