- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 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/
我试图在我的应用程序中进行长时间操作时显示一个 Activity ,该 Activity 指示覆盖(点的旋转的圆)。为此,我创建了一个具有TImage和Imagelist的无边界透明表单,我试图在主线
这是第一次尝试使用Threads,我正在尝试使用Thread复制目录,所以这就是我所做的(在我阅读 this post 之后): unit Unit1; interface uses Winapi
我有以下用 Delphi 2007 编写的服务,我发现它没有释放线程句柄。函数CurrentMemoryUsage和GetOpenHandles是返回应用程序使用的内存和句柄数量的函数。计时器每秒触发
情况。我创建了一个包含一些类的单元来解决代数问题(同余和系统),我向您展示代码: type TCongrError = class(Exception) end; type TCongruenc
据我了解,调用TThread的Synchronize将执行同步代码,就像在主线程中运行一样。假设在我的主线程中,我有一个按钮: procedure TForm3.Button1Click(Sender
我的应用程序是一个 tcp/ip 服务器,主线程仅创建一次并始终监听。当新的客户端连接时,主线程创建TClientThread类型的新线程。但是,没有正在运行的客户端线程的列表,因为这会使我的应用程序
我的程序中有一个主线程和一个单独的线程。如果单独的线程在主线程之前完成,它应该自动释放自身。如果主线程先完成,它应该释放单独的线程。 我了解 FreeOnTerminate,并且我读到您必须小心使用它
Delphi的TThread.OnTerminate帮助指出: The method assigned to the OnTerminate event is executed in the cont
我有一个 TThread 实例,我想等待用户输入。线程加载一些东西,等待用户点击一个按钮,然后继续它的任务。 我正在考虑将全局 bool 设置为 true,但我认为这对实例不太适用,并且线程必须在循环
我正在创建一个多线程应用程序,它创建了一个类 TThread 的动态数组,但对我来说神秘的是它会导致错误“访问冲突”到“创建” 代码形式: Unit UNT_Main; Interface Uses
我是 Windows 服务的新手,我需要完成这项工作...我的代码来自 here ,这只是此代码的副本。但我正在尝试从该服务发出一些 HTTP 请求。对于这项工作,我选择创建一个新线程,并在线程内执行
在线程内,我将事件排队以在主线程的上下文中运行,如下所示: TThread.Queue(nil, procedure begin AddDataToChart(SomeData) end); 现在,在
窃取 Uwe Raabe 的文章 Synchronize and Queue with Parameters我这样做: if GetCurrentThreadID = MainThreadID the
我有一个类,它是 TThread 的后代。我有一些只读的公共(public)属性。如果我的主线程在线程处于事件状态时读取这些值,我会遇到问题吗? 最佳答案 如果“只读属性”意味着 TThread 后代
我知道您需要同步(您的程序)来设置例如标签的文本。但是呢: 读取标签的文本。 切换/设置标签的启用属性。 调用其他标签过程/函数(例如 onclick 事件)。 当我需要使用synchronize时,
例如,来自 CreateTimerQueueTimer 回调提供的线程在可执行文件或dll中?与主线程具有相同的线程 ID 很重要。 procedure TMyMainClass.ExecuteMe(
我创建了一个派生自 TThread 的类,因为我希望执行一些异步操作,但是为了避免创建另一个类,我围绕该线程类构建了整个内容。不确定这是否是一个好的做法,如果我不能让它工作,那么我想我别无选择,只能重
我试图在两个独立的项目之间发送消息,但我的问题是我试图让接收器在 TThread 对象内部运行,但 WndProc 无法在对象内部工作,必须是一个函数,无论如何都可以创建TThread 内的窗口可以处
我编写了一个应用程序(使用 Delphi 2009),允许用户选择一系列可以在多个不同系统上运行的查询。为了允许查询同时运行,每个查询都使用 TADOQuery 对象在自己的线程中运行。这一切都运行良
创建一个线程(TThreadStarter),然后它将创建许多工作线程,并且必须等待它们完成才能继续。它必须在 Linux 和 Windows 下都能工作。 下面的方法似乎是一个解决方案。但这是一件好
我是一名优秀的程序员,十分优秀!