Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I need Sharemem in my Delphi dll which only exposes a function with WideString parameters?

I have a dll and a test application written in Delphi. The test application uses multiple threads to call the function exported by the dll. The exported function has a trivial thread safe implementation. When running the test application various errors (access violation, invalid pointer operation, stack overflow etc) happens or the application freezes. In some cases the application finishes without errors.

Note that these errors only happen (surface) when using multiple threads. When calling the function from the main thread only then everything works fine.

I have found that adding ShareMem to both the dll and the application stops all these kind of errors. But I don't understand why. To my knowledge ShareMem is only needed when passing long strings between the dll and the application. As far as I know WideString is not a long string.

Also according to this post ShareMem should not be required: Why can Delphi DLLs use WideString without using ShareMem?

Here is the source of the 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.

Here is the test application:

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.

Why ShareMem makes the bugs go away and is there another way to fix these bugs?

I am using Delphi XE2 and OmniThread 3.07.5.

Update - Same issue when run from a VCL application's button's on click event handler - If DoSomething uses a critical section inside then runs fine - If FText field is removed from TMyClass then no errors are reported but the application randomly freezes

like image 702
RM. Avatar asked Mar 19 '18 08:03

RM.


1 Answers

For the standard memory manager (FastMM) to support multi threading, you need to set the IsMultiThread flag.

When you use RTL for threading, this flag is automatically set. As revealed in the comments to the question, OTL also use RTL to start its threads. So the memory manager in your executable is aware of threading, but the distinct memory manager in the dll causes errors. When you use "sharemem", there is only one memory manager which is aware of threading because of OTL, so you encounter no errors.

An alternative solution, apart from using a shared memory manager, would be to set the flag also for the memory manager in the dll.

like image 136
Sertac Akyuz Avatar answered Nov 15 '22 20:11

Sertac Akyuz