Зачем мне нужен Sharemem в моей DLL Delphi, которая предоставляет только функцию с параметрами WideString?

У меня есть DLL и тестовое приложение, написанное на Delphi. Тестовое приложение использует несколько потоков для вызова функции, экспортируемой dll. Экспортируемая функция имеет тривиальную поточно-ориентированную реализацию. При запуске тестового приложения возникают различные ошибки (нарушение прав доступа, неверный указатель, переполнение стека и т. Д.) Или приложение зависает. В некоторых случаях приложение завершается без ошибок.

Обратите внимание, что эти ошибки возникают (на поверхности) только при использовании нескольких потоков. При вызове функции только из основного потока все работает нормально.

Я обнаружил, что добавление ShareMem как в dll, так и в приложение останавливает все подобные ошибки. Но я не понимаю почему. Насколько мне известно, ShareMem необходим только при передаче длинных строк между DLL и приложением. Насколько я знаю, WideString не длинная строка.

Также, согласно этому сообщению, ShareMem не требуется: почему библиотеки Delphi DLL могут использовать WideString без использования ShareMem?

Вот источник dll:

library External;

uses
  Winapi.Windows;

type
  TMyType = class
  private
    FText: string;
  end;

function DoSomething(input: WideString; out output: WideString): Bool; stdcall;
var
  x: TObject;
begin
  x := TMyType.Create;
  try
    output := x.ClassName;
  finally
    x.Free;
  end;
  Result := True;
end;

exports
  DoSomething;
begin
end.

Вот тестовое приложение:

program ConsoleTest;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  Winapi.Windows,
  OtlParallel;

function DoSomething(input: WideString; out output: WideString): Bool; stdcall; external 'External.dll' name 'DoSomething';

var
  sResult: WideString;

begin
  try
    Parallel.&For(0, 500).Execute(procedure(value: Integer)
    var
      sResult: WideString;
    begin
      DoSomething('hhh', sResult);
    end);
    WriteLn('Done');
    ReadLn;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Почему ShareMem устраняет ошибки и есть ли другой способ исправить эти ошибки?

Я использую Delphi XE2 и OmniThread 3.07.5.

Обновление - та же проблема при запуске из обработчика события нажатия кнопки приложения VCL. - Если DoSomething использует критический раздел внутри, то работает нормально. Если поле FText удалено из TMyClass, то об ошибках не сообщается, но приложение случайно зависает

1 ответ

Решение

Чтобы стандартный менеджер памяти (FastMM) поддерживал многопоточность, необходимо установить IsMultiThread флаг.

Когда вы используете RTL для многопоточности, этот флаг устанавливается автоматически. Как показано в комментариях к вопросу, OTL также использует RTL для запуска своих потоков. Таким образом, диспетчер памяти в вашем исполняемом файле знает о многопоточности, но отдельный диспетчер памяти в DLL вызывает ошибки. Когда вы используете "sharemem", существует только один менеджер памяти, который знает о многопоточности из-за OTL, поэтому вы не встретите ошибок.

Альтернативное решение, помимо использования диспетчера разделяемой памяти, состоит в том, чтобы установить флаг также для диспетчера памяти в dll.

Другие вопросы по тегам