Смешивание атомарной операции с неатомарной операцией - PullRequest
0 голосов
/ 09 января 2019

В исходном коде delphi мы имеем:

class function TNetEncoding.GetBase64Encoding: TNetEncoding;
var
  LEncoding: TBase64Encoding;
begin
  if FBase64Encoding = nil then
  begin
    LEncoding := TBase64Encoding.Create;
    if AtomicCmpExchange(Pointer(FBase64Encoding), Pointer(LEncoding), nil) <> nil then
      LEncoding.Free
{$IFDEF AUTOREFCOUNT}
    else
      FBase64Encoding.__ObjAddRef
{$ENDIF AUTOREFCOUNT};
  end;
  Result := FBase64Encoding;
end;

но я не понимаю, они смешивают атомарную операцию (AtomicCmpExchange(Pointer(FBase64Encoding), Pointer(LEncoding), nil) с неатомарную операцию как if FBase64Encoding = nil then и Result := FBase64Encoding;

Разве это не ошибка?

1 Ответ

0 голосов
/ 09 января 2019

В комментариях вы даете понять, что вас беспокоит то, что незащищенные операции с памятью могут порваться. Под разрывом мы понимаем, что поток чтения читает переменную, когда она частично записана.

В целом это серьезная проблема, но в этом случае разрыв не произойдет. Причина в том, что согласованный доступ к памяти гарантированно не порвется. Когда операция памяти выровнена, как эта, читатель не может прочитать частично записанную переменную. Обычно это обеспечивается аппаратной шиной, сериализующей весь доступ к памяти в пределах одной строки кэша.

Итак, нет, это не ошибка, код правильный.

Сам код используется для ленивого создания синглтона. Обычный способ сделать это безопасным способом - это двойная проверка блокировки. Этот код использует альтернативную технику, которая избегает блокировки. Вместо этого код потенциально позволяет нескольким потокам спекулятивно создавать синглтон. Если более одного потока удается создать объект, побеждает первый успешный объект, а другие потоки уничтожают свои экземпляры и используют тот, который создан потоком-победителем.

Подход без блокировок работает хорошо, при условии, что можно создавать дополнительные экземпляры, а затем уничтожать их. Но это не всегда так. Например, может быть слишком дорого создавать несколько копий экземпляра. В таких случаях лучше использовать подход, основанный на блокировке.

...