Зачем мне нужен 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.