【发布时间】:2013-07-30 14:59:27
【问题描述】:
我的 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;
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;
当我尝试从 1 个线程使用此库时 - 一切正常。当我创建许多线程调用函数AddToLog 时,问题就开始了(每个线程都有自己的类对象)。有一段时间我会赶上Access Violation 或Invalid pointer operation。
我进行了一些研究并指出如果变量Temp2 具有WideString 类型,则一切正常。另一种解决方案是将互斥锁移到库代码中(它只是一个“研究”代码):
function AddToLog( PLogger: Cardinal; BufStr: PWideChar ): Word; stdcall;
begin
WaitForSingleObject( TLogger(PLogger).FMutex, INFINITE );
Result := TLogger(PLogger).AddToLog( BufStr );
ReleaseMutex( TLogger(PLogger).FMutex );
end;
第二种解决方案对我不利,因为每个对象都有自己的互斥锁(想法是,如果两个对象必须与一个文件一起使用,则它们具有相同的互斥锁以相互等待;如果两个对象必须与不同的文件一起使用,则它们具有不同的互斥体并并行工作)。
我试图解决这个问题 2 天,但我不明白出了什么问题。字符串转换如何导致这样的问题?
【问题讨论】:
-
在我看来您删除了太多代码。即使您删除了互斥锁,并且即使所有线程共享同一个记录器实例,您在此处拥有的代码也是线程安全的。你需要一个 SSCCE。
-
你设置
IsMultiThread:= True;在 DLL 中? -
@TOndrej 啊,我敢打赌就是这样。使用
IsMultiThread作为False,堆分配器将不是线程安全的。我建议您将其添加为答案。
标签: multithreading delphi class dll