Come dovrebbe “Double-Checked Locking” da attuare in Delphi?
-
11-10-2019 - |
Domanda
In C #, il seguente codice (da questa pagina ) può essere utilizzato per pigramente istanziare una classe Singleton in un modo thread-safe:
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
lock(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
Quale sarebbe il filo di codice Delphi sicura equivalente?
L'articolo cita anche due problemi con ricontrollato blocco in Java:
- è possibile che il nuovo oggetto viene costruito prima si fa riferimento al punto helper il significato oggetto creato che due oggetti vengono creati
- è possibile che si fa riferimento helper a punto in un blocco di memoria, mentre è ancora creato l'oggetto che significa che un riferimento a un oggetto incompleta verrà restituito
Così, mentre il codice del C # e la versione di Java nel look articolo citato quasi identiche, solo la versione C # funziona come previsto. Il che porta alla domanda supplementare se esistono anche questi due problemi in una versione di Delphi di interblocco ricontrollato?
Soluzione
Usa System.TMonitor per bloccare l'istanza di oggetto in modo sicuro thread.
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;
Per ulteriori sguardo riferimento Blocco mio oggetto ..., per favore! Allen Bauer . In realtà, il rappresentante. Deduco da questo dovrebbe andare ad Allen.
Altri suggerimenti
Naturalmente, vale sempre la pena ricordare che doppio controllo è rotto . Questo problema risulta non da applicare al modello di memoria X 86, ma vale sempre la pena tenendo a mente per il futuro. Sono sicuro che ci sarà la versione di Delphi ad un certo punto che verrà eseguito su una piattaforma con un modello di memoria che è afflitto da questo problema.
Embarcadero hanno iniziato a utilizzare una versione senza blocchi di questo modello con interlocked confronto / scambio. Ad esempio:
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;
Mi rendo conto che questa non è una risposta alla domanda, ma non ha veramente in forma in un commento!