Как реализовать двойную проверку блокировки в Delphi? - PullRequest
5 голосов
/ 18 декабря 2010

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

  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-версии Double-Checked Locking?

Ответы [ 2 ]

7 голосов
/ 18 декабря 2010

Используйте 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;

Для дальнейшего ознакомления посмотрите на Заблокируйте мой объект ..., пожалуйста! из Аллен Бауэр .На самом деле, респ.Я понял, что из этого следует пойти к Аллену.

2 голосов
/ 18 декабря 2010

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

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

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;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...