Делает ли Delphi переменную перед созданием объекта?
Делает ли Delphi переменную экземпляра до полного создания объекта?
Другими словами, учитывая переменную:
var
customer: TCustomer = nil;
Затем мы создаем клиента и присваиваем его переменной:
customer := TCustomer.Create;
Возможно ли, чтоcustomer
может быть неnil
, но не указывают на полностью построенныйTCustomer
?
Это становится проблемой при выполнении отложенной инициализации:
function SacrifialCustomer: TCustomer;
begin
if (customer = nil) then
begin
criticalSection.Enter;
try
customer := TCustomer.Create;
finally
criticalSection.Leave;
end;
end;
Result := customer;
end;
Ошибка в строке:
if (customer = nil)
Возможно, что другой поток вызывает:
customer := TCustomer.Create;
и переменной присваивается значение до начала строительства, Это заставляет потокassume тотcustomer
является допустимым объектом просто потому, что переменная назначена.
Может ли эта многопоточная ошибка синглтона произойти в Delphi (5)?
Bonus Question
Есть ли принятый, потокобезопасный,однократная инициализация шаблон дизайна для Delphi? Многие люди реализовалиsingletons в Delphi путем переопределенияNewInstance
а такжеFreeInstance
; их реализации потерпят неудачу в нескольких потоках.
Строго говоря, я не после ответа о том, как реализовать иsingleton, ноlazy-initialization, В то время какsingletons Можноuse ленивая инициализация,lazy initialization не ограничивается одиночками.
Update
Два человека предложили ответэто содержит распространенную ошибку.broken double-checked locking algorithm translated to Delphi:
// Broken multithreaded version
// "Double-Checked Locking" idiom
if (customer = nil) then
begin
criticalSection.Enter;
try
if (customer = nil) then
customer := TCustomer.Create;
finally
criticalSection.Leave;
end;
end;
Result := customer;
ОтВикипедия:
Intuitively, this algorithm seems like an efficient solution to the problem. However, this technique has many subtle problems and should usually be avoided.
Еще одно ошибочное предложение:
function SacrificialCustomer: TCustomer;
var
tempCustomer: TCustomer;
begin
tempCustomer = customer;
if (tempCustomer = nil) then
begin
criticalSection.Enter;
try
if (customer = nil) then
begin
tempCustomer := TCustomer.Create;
customer := tempCustomer;
end;
finally
criticalSection.Leave;
end;
end;
Result := customer;
end;
Update
Я создал некоторый код и посмотрел на окно процессора. Кажется, что этот компилятор с моими настройками оптимизации в этой версии Windows, с этим объектом, сначала создает объект,then назначает переменную:
customer := TCustomer.Create;
mov dl,$01
mov eax,[$0059d704]
call TCustomer.Create
mov [customer],eax;
Result := customer;
mov eax,[customer];
Конечно, я не могу сказать, что это всегда гарантировано.