多线程应用程序中的DLL和类

Ant*_*hal 8 delphi dll multithreading class

我的DLL中有一个类.这个DLL提供了一个"接口"来创建这个类的对象并调用它们的方法.

类代码(简化):

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

DLL代码

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

当我试图从1个线程使用这个库时 - 一切都很好.当我创建许多线程AddToLog以随机周期调用函数时(每个线程都有自己的类对象),问题就开始了.在某些时候,我抓住Access ViolationInvalid pointer operation.我做了一些研究,并指出如果变量Temp2WideString类型,一切都可以.另一个解决方案是将互斥锁移动到库代码(它只是一个"研究"代码):

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

第二个解决方案对我不利,因为每个对象都有自己的互斥锁(想法是如果两个对象必须使用一个文件,它们具有相同的互斥锁以便彼此等待;如果两个对象必须使用不同的文件,它们具有不同的互斥锁并行工作).

我试图解决这个问题2天,但我无法理解出了什么问题.字符串转换如何导致此类问题?

Ond*_*lle 14

放下以下行:

IsMultiThread := True;
Run Code Online (Sandbox Code Playgroud)

作为DLL项目主代码块中的第一行.这将指示内存管理器切换到线程安全模式.

这可以解释之间的行为差异AnsiString,并WideString因为AnsiString是由德尔福内存管理器分配,并WideString在COM堆分配.当IsMultiThreadFalse时,德尔福内存管理器不是线程安全的,但COM堆始终是线程安全的.