Как должна быть реализована “Блокировка с двойной проверкой” в Delphi?

StackOverflow https://stackoverflow.com/questions/4475080

Вопрос

В C # следующий код (из это page) может использоваться для ленивого создания экземпляра одноэлементного класса потокобезопасным способом:

  class Foo {
        private volatile Helper helper = null;
        public Helper getHelper() {
            if (helper == null) {
                lock(this) {
                    if (helper == null)
                        helper = new Helper();
                }
            }
            return helper;
        }
    }

Каким был бы эквивалентный потокобезопасный код Delphi?


В статье также упоминаются две проблемы с двойной проверкой блокировки в Java:

  • возможно, что новый объект создается до того, как будет сделана вспомогательная ссылка, указывающая на вновь созданный объект, что означает, что создаются два объекта
  • возможно, что вспомогательная ссылка делается для указания на блок памяти, пока объект все еще создается, что означает, что будет возвращена ссылка на неполный объект

Таким образом, хотя код версии C # и Java в упомянутой статье выглядят почти идентично, только версия C # работает так, как ожидалось.Что приводит к дополнительному вопросу, существуют ли эти две проблемы также в версии Delphi с двойной проверкой блокировки?

Это было полезно?

Решение

Используйте System.TMonitor для блокировки экземпляра объекта потокобезопасным способом.

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;

Для получения дополнительной информации посмотрите на Заблокируйте мой объект ..., пожалуйста! От Allen Bauer.На самом деле, представитель.Я делаю вывод, что из этого следует обратиться к Аллену.

Другие советы

Конечно, всегда стоит помнить об этом Дважды проверенный замок сломан.Оказывается, эта проблема неприменима к модели памяти x86, но ее всегда стоит иметь в виду на будущее.Я уверен, что в какой-то момент появится версия Delphi, которая будет работать на платформе с моделью памяти, подверженной этой проблеме.

Embarcadero начали использовать версию этого шаблона без блокировок с блокировкой compare / exchange.Например:

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;

Я понимаю, что это не ответ на вопрос, но на самом деле это не вписывалось в комментарий!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top