gpt4 book ai didi

multithreading - 仅按需从 TThread 动态初始化和调用 LoadLibrary 一次

转载 作者:行者123 更新时间:2023-12-03 18:18:24 26 4
gpt4 key购买 nike

我有一个 Delphi DLL,需要从我的主 UI 应用程序或工作线程调用它。

我不想每次调用 DLL 时都调用 LoadLibrary/FreeLibrary。但是,我也不想在我的应用程序初始化部分加载它。因为我可能在应用程序的生命周期内根本不使用 DLL。

所以我需要的是第一个调用者(线程或主 UI)来初始化和加载 DLL。DLL 将在终结部分卸载。我意识到我需要一些同步。所以我使用了一个关键部分,但我似乎无法让它工作。

只有一个 线程应该尝试加载DLL。如果失败,其他线程不应尝试一次又一次地加载 DLL。

同步未按预期工作!
有人可以提出原因吗?

MCVE:

program Project1;
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils,
Classes;

const
MyDLL = 'MyDLL.dll';

type
TDLLProcessProc = function(A: Integer): Integer; stdcall;

var
DLLProc: TDLLProcessProc = nil;
DLLModule: HMODULE = 0;
DLLInitialized: Boolean = False;
DLLInitialized_OK: Boolean = False;
CS: TRTLCriticalSection;

procedure InitDLLByFirstCall;
begin
if DLLModule = 0 then
begin
if DLLInitialized then Exit;
EnterCriticalSection(CS);
try
if DLLInitialized then Exit;
DLLInitialized := True;
DLLModule := LoadLibrary(MyDLL);
if DLLModule = 0 then RaiseLastWin32Error;
DLLProc := GetProcAddress(DLLModule, 'Process');
if @DLLProc = nil then RaiseLastWin32Error;
DLLInitialized_OK := True;
finally
LeaveCriticalSection(CS);
end;
end;
end;

function DLLProcess(A: Integer): Integer;
begin
InitDLLByFirstCall;
if not DLLInitialized_OK then
raise Exception.Create('DLL was not initialized OK');
Result := DLLProc(A);
end;

type
TDLLThread = class(TThread)
private
FNum: Integer;
public
constructor Create(CreateSuspended: Boolean; ANum: Integer);
procedure Execute; override;
end;

constructor TDLLThread.Create(CreateSuspended: Boolean; ANum: Integer);
begin
FreeOnTerminate := True;
FNum := ANum;
inherited Create(CreateSuspended);
end;

procedure TDLLThread.Execute;
var
RetValue: Integer;
begin
try
RetValue := DLLProcess(FNum);
Sleep(0);
Writeln('TDLLThread Result=> ' + IntToStr(RetValue));
except
on E: Exception do
begin
Writeln('TDLLThread Error: ' + E.Message);
end;
end;
end;

var
I: Integer;

begin
InitializeCriticalSection(CS);
try
// First 10 thread always fail!
for I := 1 to 10 do
TDLLThread.Create(False, I);
Readln;

for I := 1 to 10 do
TDLLThread.Create(False, I);
Readln;
finally
DeleteCriticalSection(CS);
end;
end.

动态链接库:

library MyDLL;

uses
Windows;

{$R *.res}

function Process(A: Integer): Integer; stdcall;
begin
Result := A;
end;

exports
Process;

begin
IsMultiThread := True;
end.

最佳答案

您需要修改您的代码,以便仅在所有初始化完成后设置在 InitDLLByFirstCall 开始时检查的条件变量。因此,DLL 句柄是一个糟糕的选择。

其次,您需要在临界区内外使用相同的条件变量 - 如果为此使用 DLLInitialized,那么 DLLInitialized_OK 也不是 DLLModule

为了让事情更容易推理,您应该尝试使用最少数量的变量。像下面这样的东西应该可以工作:

var
DLLProc: TDLLProcessProc = nil;
DLLInitialized: Boolean = False;
CS: TRTLCriticalSection;

procedure InitDLLByFirstCall;
var
DLLModule: HMODULE;
begin
if DLLInitialized then
Exit;

EnterCriticalSection(CS);
try
if not DLLInitialized then
try
DLLModule := LoadLibrary(MyDLL);
Win32Check(DLLModule <> 0);

DLLProc := GetProcAddress(DLLModule, 'Process');
Win32Check(Assigned(DLLProc));
finally
DLLInitialized := True;
end;
finally
LeaveCriticalSection(CS);
end;
end;

function DLLProcess(A: Integer): Integer;
begin
InitDLLByFirstCall;
if @DLLProc = nil then
raise Exception.Create('DLL was not initialized OK');
Result := DLLProc(A);
end;

如果您不想检查 DLLProcess 中的函数地址,那么您还可以为 DLLInitialized 变量使用整数或枚举,为未初始化失败成功

关于multithreading - 仅按需从 TThread 动态初始化和调用 LoadLibrary 一次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34401028/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com