Ich habe gerade festgestellt, dass ich an einer Stelle in meinem Code die return-Anweisung innerhalb des Schlosses und irgendwann außerhalb habe. Welches ist das beste?
1)
void example()
{
lock (mutex)
{
//...
}
return myData;
}
2)
void example()
{
lock (mutex)
{
//...
return myData;
}
}
Welches soll ich verwenden?
c#
.net
multithreading
mutex
Patrick Desjardins
quelle
quelle
Antworten:
Im Wesentlichen, was auch immer den Code einfacher macht. Single Point of Exit ist ein schönes Ideal, aber ich würde den Code nicht aus der Form bringen, um ihn zu erreichen ... Und wenn die Alternative darin besteht, eine lokale Variable (außerhalb des Schlosses) zu deklarieren, sie zu initialisieren (innerhalb des Schlosses) und Wenn Sie es dann zurückgeben (außerhalb des Schlosses), würde ich sagen, dass ein einfaches "Return Foo" innerhalb des Schlosses viel einfacher ist.
Um den Unterschied in IL zu zeigen, lassen Sie uns Folgendes codieren:
(Beachten Sie, dass ich gerne behaupten würde, dass dies
ReturnInside
ein einfacheres / saubereres Stück C # ist.)Und schauen Sie sich die IL an (Release-Modus usw.):
Auf IL-Ebene sind sie also identisch (ich habe etwas gelernt ;-p). Als solches ist der einzig sinnvolle Vergleich das (höchst subjektive) Gesetz des lokalen Codierungsstils ... Ich bevorzuge der
ReturnInside
Einfachheit halber, aber ich würde mich auch nicht darüber aufregen.quelle
ret
in einer.try
Region befinden.Es macht keinen Unterschied; Sie werden beide vom Compiler in dasselbe übersetzt.
Zur Verdeutlichung wird beides effektiv in etwas mit der folgenden Semantik übersetzt:
quelle
Ich würde die Rückgabe definitiv in das Schloss stecken. Andernfalls riskieren Sie, dass ein anderer Thread in die Sperre eindringt und Ihre Variable vor der return-Anweisung ändert, sodass der ursprüngliche Aufrufer einen anderen Wert als erwartet erhält.
quelle
Es hängt davon ab, ob,
Ich werde hier gegen den Strich gehen. Ich würde im Allgemeinen innerhalb des Schlosses zurückkehren.
Normalerweise ist die Variable mydata eine lokale Variable. Ich deklariere gerne lokale Variablen, während ich sie initialisiere. Ich habe selten die Daten, um meinen Rückgabewert außerhalb meiner Sperre zu initialisieren.
Ihr Vergleich ist also tatsächlich fehlerhaft. Während der Unterschied zwischen den beiden Optionen im Idealfall so ist, wie Sie es geschrieben haben, was Fall 1 zu nicken scheint, ist es in der Praxis etwas hässlicher.
vs.
Ich finde Fall 2 wesentlich leichter zu lesen und schwerer zu vermasseln, insbesondere bei kurzen Ausschnitten.
quelle
Wenn Sie der Meinung sind, dass das Schloss draußen besser aussieht, aber seien Sie vorsichtig, wenn Sie den Code in Folgendes ändern:
Wenn f () mit gehaltenem Schloss aufgerufen werden muss, muss es sich offensichtlich innerhalb des Schlosses befinden, da es sinnvoll ist, die Rückgabe aus Gründen der Konsistenz innerhalb des Schlosses zu halten.
quelle
In der Dokumentation zu MSDN finden Sie ein Beispiel für die Rückkehr aus dem Inneren des Schlosses. Von den anderen Antworten hier scheint es IL ziemlich ähnlich zu sein, aber für mich scheint es sicherer, aus dem Schloss zurückzukehren, da Sie dann nicht das Risiko eingehen, dass eine Rückgabevariable von einem anderen Thread überschrieben wird.
quelle
Um anderen Entwicklern das Lesen des Codes zu erleichtern, würde ich die erste Alternative vorschlagen.
quelle
lock() return <expression>
Aussagen immer:1) Sperre eingeben
2) macht einen lokalen (thread-sicheren) Speicher für den Wert des angegebenen Typs,
3) füllt das Geschäft mit dem von zurückgegebenen Wert
<expression>
,4) Ausgangssperre
5) Geben Sie den Laden zurück.
Dies bedeutet, dass der von der lock-Anweisung zurückgegebene Wert vor der Rückgabe immer "gekocht" wird.
Mach dir keine Sorgen
lock() return
, hör hier niemandem zu))quelle
Hinweis: Ich glaube, dass diese Antwort sachlich korrekt ist, und ich hoffe, dass sie auch hilfreich ist, aber ich bin immer froh, sie auf der Grundlage konkreter Rückmeldungen zu verbessern.
Um die vorhandenen Antworten zusammenzufassen und zu ergänzen:
Die akzeptierte Antwort zeigt, dass unabhängig davon, welche Syntaxform Sie in Ihrem C # -Code wählen , im IL-Code - und damit zur Laufzeit -
return
dies erst nach dem Aufheben der Sperre geschieht.return
Inneren deslock
Blocks genau genommen den Kontrollfluss falsch darstellt [1] , ist es syntaktisch praktisch , da die Notwendigkeit, den Rückgabewert in einem Aux zu speichern, entfällt. lokale Variable (außerhalb des Blocks deklariert, damit sie mit einerreturn
außerhalb des Blocks verwendet werden kann) - siehe Antwort von Edward KMETT .Getrennt - und dieser Aspekt ist nebensächlich auf die Frage, aber immer noch von Interesse (sein kann Ricardo Villamil Antwort versucht es zu lösen, aber falsch, glaube ich) - eine Kombination
lock
Anweisung mit einerreturn
Aussage - dh Wert zu erhalten , umreturn
in einem Block geschützt von die gleichzeitige Zugriff - nur dann sinnvoll „schützt“ den Rückgabewert in dem Anrufer ‚s Umfang , wenn es tatsächlich nicht einmal erhalten muß schütz , die in den folgenden Szenarien gelten:Wenn der zurückgegebene Wert ein Element aus einer Sammlung ist, das nur durch Hinzufügen und Entfernen von Elementen geschützt werden muss , nicht durch Änderungen der Elemente selbst und / oder ...
... wenn der zurückgegebene Wert eine Instanz eines Werttyps oder einer Zeichenfolge ist .
In jedem anderen Fall muss die Sperre vom Aufrufer durchgeführt werden , nicht (nur) innerhalb der Methode.
[1] Theodor Zoulias weist darauf hin , dass das technisch gilt auch für die Platzierung
return
innerhalbtry
,catch
,using
,if
,while
,for
, ... Aussagen; Es ist jedoch der spezifische Zweck derlock
Erklärung, der wahrscheinlich zu einer Überprüfung des tatsächlichen Kontrollflusses einlädt, wie aus dieser Frage hervorgeht, die gestellt wurde und viel Aufmerksamkeit erhalten hat.[2] Durch den Zugriff auf eine Instanz vom Werttyp wird ausnahmslos eine threadlokale Kopie davon auf dem Stapel erstellt. Obwohl Zeichenfolgen technisch Instanzen vom Referenztyp sind, verhalten sie sich effektiv wie Instanzen vom Typ "Wert".
quelle
lock
und leiten die Bedeutung aus der Platzierung der Rückgabeerklärung ab. Welches ist eine Diskussion ohne Bezug zu dieser Frage IMHO. Auch finde ich die Verwendung von "falsch dargestellt" ziemlich störend. Wenn Rückkehr von einerlock
misrepresents des Ablaufs der Steuerung, dann könnte dieselbe von einem für die Rückführung gesagt werdentry
,catch
,using
,if
,while
,for
, und anderes Konstrukt der Sprache. Es ist, als würde man sagen, dass das C # mit falschen Darstellungen des Kontrollflusses durchsetzt ist. Jesus ...try
,,if
... Ich persönlich neige nicht dazu, darüber nachzudenken, aber im Zusammenhang mitlock
speziell der Frage stellte sich für mich - und wenn sie nicht auch für andere aufgetaucht wäre, wäre diese Frage niemals gestellt worden und die akzeptierte Antwort hätte nicht große Anstrengungen unternommen, um das wahre Verhalten zu untersuchen.