Comment « Immobilisation Vérifié double » être mis en œuvre dans Delphi?
-
11-10-2019 - |
Question
En C #, le code suivant (de cette page ) peut être utilisé pour paresseusement instancier une classe singleton dans un fil de manière sûre:
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
lock(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
Quel serait le fil équivalent en toute sécurité le code Delphi?
L'article mentionne également deux problèmes avec double verrouillage Démarrée Java:
- il est possible que le nouvel objet est construit avant la référence d'aide est faite à un point au sens de l'objet nouvellement créé que deux objets sont créés
- il est possible que la référence d'aide est faite à un point à un bloc de mémoire alors que l'objet est toujours en cours de création qui signifie qu'une référence à un objet incomplet sera retourné
Ainsi, alors que le code du C # et la version Java dans le regard de l'article mentionné presque identique, seule la version C # fonctionne comme prévu. Ce qui nous amène à la question supplémentaire si ces deux problèmes existent aussi dans une version Delphi de verrouillage revérifié?
La solution
Utilisez System.TMonitor pour verrouiller l'instance d'objet dans un fil de manière sûre.
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;
Pour plus d'aspect de référence à verrouillage mon objet ..., s'il vous plaît! de Allen Bauer . En fait, le représentant. Je déduis devrait aller à Allen.
Autres conseils
Bien sûr, il est toujours bon de rappeler que verrouillage revérifié est cassé . Cette question se révèle ne pas appliquer au modèle de mémoire x86 mais il vaut toujours la peine gardant à l'esprit pour l'avenir. Je suis sûr qu'il y aura la version Delphi à un moment qui se déroulera sur une plate-forme avec un modèle de mémoire qui est affligé par cette question.
Embarcadero ont commencé à utiliser une version sans verrou de ce modèle avec comparaison / échange agrafé. Par exemple:
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;
Je sais que ce n'est pas une réponse à la question, mais il ne correspondait pas vraiment dans un commentaire!