多线程应用程序中的DLL和类(DLL and class in multithreaded application)

编程入门 行业动态 更新时间:2024-10-26 14:31:11
多线程应用程序中的DLL和类(DLL and class in multithreaded application)

我的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天,但我不明白出了什么问题。 字符串转换如何导致这样的问题?

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?

最满意答案

放置以下行:

IsMultiThread := True;

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

这将解释AnsiString和WideString之间的行为差​​异,因为AnsiString由Delphi内存管理器分配,而WideString分配在COM堆上。 当IsMultiThread为False ,Delphi内存管理器不是线程安全的,但COM堆始终是线程安全的。

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.

更多推荐

本文发布于:2023-07-05 07:48:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1034847.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:多线程   应用程序   DLL   application   multithreaded

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!