为什么我需要在我的Delphi dll中使用Sharemem,它只使用WideString参数公开一个函数?

RM.*_*RM. 9 delphi dll multithreading widestring omnithreadlibrary

我有一个用Delphi编写的dll和测试应用程序.测试应用程序使用多个线程来调用dll导出的函数.导出的函数具有简单的线程安全实现.运行测试应用程序时会发生各种错误(访问冲突,无效指针操作,堆栈溢出等)或应用程序冻结.在某些情况下,应用程序完成没有错误.

请注意,这些错误仅在使用多个线程时发生(表面).从主线程调用函数时,一切正常.

我发现将ShareMem添加到dll和应用程序会停止所有这些错误.但我不明白为什么.据我所知,只有在dll和应用程序之间传递长字符串时才需要ShareMem.据我所知,WideString不是一个长字符串.

另外根据这篇文章,不应该要求ShareMem: 为什么Delphi DLL可以在不使用ShareMem的情况下使用WideString?

这是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.
Run Code Online (Sandbox Code Playgroud)

这是测试应用程序:

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.
Run Code Online (Sandbox Code Playgroud)

为什么ShareMem会让错误消失,还有另一种解决这些错误的方法吗?

我使用的是Delphi XE2和OmniThread 3.07.5.

更新 - 从单击事件处理程序的VCL应用程序按钮运行时出现相同的问题 - 如果DoSomething使用内部的关键部分然后运行正常 - 如果从TMyClass中删除FText字段,则不报告错误但应用程序随机冻结

Ser*_*yuz 9

对于支持多线程的标准内存管理器(FastMM),您需要设置IsMultiThread标志.

使用RTL进行线程处理时,会自动设置此标志.正如对问题的评论中所揭示的,OTL也使用RTL来启动它的线程.因此,可执行文件中的内存管理器知道线程,但dll中的独特内存管理器会导致错误.当您使用"sharemem"时,只有一个内存管理器因OTL而知道线程,因此您不会遇到任何错误.

除了使用共享内存管理器之外,另一种解决方案是为dll中的内存管理器设置标志.