Wie soll „Double-Checked Locking“ in Delphi realisiert werden?
-
11-10-2019 - |
Frage
In C #, der folgende Code (von dieser Seite) können zu träge verwendet werden instantiate eine Singleton-Klasse in einem Thread sichere Art und Weise:
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
lock(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
Was der äquivalent Thread-sicher Delphi-Code wäre?
Der Artikel erwähnt auch zwei Probleme mit doppelt geprüft Locking in Java:
- ist es möglich, dass das neue Objekt aufgebaut wird, bevor der Helfer Bezug auf Punkt, an der neu erstellten Objekt Bedeutung gemacht wird, dass zwei Objekte erzeugt
- ist es möglich, dass der Helfer Bezug auf Punkt auf einem Speicherblock gemacht wird, während das Objekt noch erstellt wird was bedeutet, dass ein Verweis auf ein unvollständiges Objekt wird zurückgegeben
So, während der Code der C # und die Java-Version in dem erwähnten Artikel Blick fast identisch, nur die C # -Version funktioniert wie erwartet. Das führt zu der zusätzlichen Frage, ob diese beiden auch Probleme in einer Delphi-Version von Double-Checked Locking existieren?
Lösung
Verwenden System.TMonitor die Objektinstanz in einem Thread sichere Art und Weise zu sperren.
function TFoo.GetHelper(): THelper;
begin
if not Assigned(FHelper) then
begin
System.MonitorEnter(Self);
try
if not Assigned(FHelper) then
FHelper := THelper.Create();
finally
System.MonitorExit(Self);
end;
end;
Result := FHelper;
end;
Für weitere Referenz Blick auf sperren mein Objekt ..., bitte! von Aller Bauer . In der Tat, die rep. Ich entnehme dies sollte zu Allen gehen.
Andere Tipps
Natürlich ist es immer zu bedenken, dass doppelt geprüft Locking ist Gebrochene . Dieses Problem stellt sich heraus, nicht auf das x86-Speichermodell anzuwenden, aber es ist immer zu bedenken, für die Zukunft. Ich bin sicher, es wird Delphi-Version an einem gewissen Punkt, die auf einer Plattform mit einem Speichermodell ausgeführt werden, die von diesem Problem betroffen ist.
Embarcadero hat mit einer Lock-freier Version dieses Musters mit verzahnte vergleichen / Austausch gestartet. Zum Beispiel:
class function TEncoding.GetUnicode: TEncoding;
var
LEncoding: TEncoding;
begin
if FUnicodeEncoding = nil then
begin
LEncoding := TUnicodeEncoding.Create;
if InterlockedCompareExchangePointer(Pointer(FUnicodeEncoding), LEncoding, nil) <> nil then
LEncoding.Free;
end;
Result := FUnicodeEncoding;
end;
Ich weiß, dies auf die Frage keine Antwort, aber es nicht wirklich in einem Kommentar passen!