DLL and class in multithreaded application

青春壹個敷衍的年華 提交于 2020-01-03 08:08:08

问题


I have a class inside my DLL. And this DLL provides an "interface" to create objects of this class and call their methods.

Class code (simplified):

TLogger = class
  private
    //
  public
    function AddToLog(sBuf: PWideChar): Word;
    constructor Create(Name: PWideChar);
    destructor Destroy; override;
end;

constructor Create(Name: PWideChar);
begin
  //
end; 

destructor TLogger.Destroy;
begin
  //
end;

function TLogger.AddToLog(sBuf: PWideChar): Word;
var
  Temp1 : WideString;
  Temp2 : AnsiString;

begin
  Result := NO_ERRORS;

  WaitForSingleObject( FMutex, INFINITE );

  Temp1 := 'a';
  Temp2 := Temp1;

  //

  ReleaseMutex( FMutex );
end;

DLL code

function CreateLogger( LogFileName: PWideChar; PLogger: PCardinal): Word; stdcall;
begin
  try
    PLogger^ := Cardinal(TLogger.Create(LogFileName));
    Result := NO_ERRORS;
  except
    Result := ERR_CREATE_OBJECT;
  end;
end;

function DestroyLogger( PLogger: Cardinal ): Word; stdcall;
begin
  try
    TLogger(PLogger).Free;
    Result := NO_ERRORS;
  except
    Result := ERR_OBJECT_NOT_FOUND;
  end;
end;

function AddToLog( PLogger: Cardinal; BufStr: PWideChar ): Word; stdcall;
begin
  try
    Result := TLogger(PLogger).AddToLog( BufStr );
  except
    Result := ERR_OBJECT_NOT_FOUND;
  end;
end;

When I'm trying to use this library from 1 thread - everything is OK. The problems start when I create many threads that call function AddToLog with random periods (each thread has it's own object of the class). In some time I catch Access Violation or Invalid pointer operation. I've made some research and pointed out that if variable Temp2 has WideString type everything is OK. Another solution is to move mutex to the library code (it's just a "research" code):

function AddToLog( PLogger: Cardinal; BufStr: PWideChar ): Word; stdcall;
begin
  WaitForSingleObject( TLogger(PLogger).FMutex, INFINITE );
  Result := TLogger(PLogger).AddToLog( BufStr );
  ReleaseMutex( TLogger(PLogger).FMutex );
end;

The second solution is bad for me because each object has it's own mutex (idea is that if two objects must work with one file, they have the same mutex to wait each other; if two objects must work with different files, they have different mutexes and work in parallel).

I'm trying to solve this problem for 2 days but I can't understand what goes wrong. How string cast can cause such problem?


回答1:


Put the following line:

IsMultiThread := True;

as the first line in your DLL project's main code block. This will instruct the memory manager to switch to a thread-safe mode.

This would explain a behaviour difference between AnsiString and WideString because AnsiString is allocated by the Delphi memory manager, and WideString is allocated on the COM heap. When IsMultiThread is False, the Delphi memory manager is not thread-safe, but the COM heap is always thread-safe.



来源:https://stackoverflow.com/questions/17950545/dll-and-class-in-multithreaded-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!