gpt4 book ai didi

c++ - 调用 FreeLibrary 时可能出现死锁

转载 作者:可可西里 更新时间:2023-11-01 16:18:46 24 4
gpt4 key购买 nike

我必须在 Delphi XE7 中编写一个 DLL。我想在 DLL 中使用 TParallel.For。 DLL 被加载到 C++ 应用程序中,一切正常。但是,当应用程序终止或调用 FreeLibrary 时,应用程序会挂起。如果我删除所有 TParallel.For 循环并将它们替换为标准循环,应用程序将正常退出。

TParallel.For 循环非常简单:

TParallel.For(0, inImage.Height -1, 
Procedure(ty : integer)
begin
SomeProcedure(ty);
end);

如果我使用完全相同的代码创建一个 Delphi 应用程序,一切都会完美无缺。

经过大量研究和调试后,似乎有一个死锁阻止了 C++ 应用程序在调用 FreeLibrary 时退出,但我找不到 TParallel 中的问题所在。

总结一下情况:

  • TParallel.For 循环全部完成并产生正确的结果。
  • 完全相同的 TParallel.For 代码在 Delphi .exe 中工作正常。
  • 已加载 DLL,并从 C++ 应用程序中正确调用和执行函数。
  • 如果没有 TParallel.For 循环,C++ 应用程序将正确退出。
  • 如果存在 TParallel.For 循环,C++ 应用程序将挂起。
  • 我猜测在调用 FreeLibrary 时发生了死锁。
  • 如果我使用 OTL 线程库,一切正常。

我的问题是:

有没有其他人经历过这种行为?

在这种情况下找到死锁的好的调试策略是什么?

非常感谢任何建议。

更新

好的,所以如果你想要最小的、完整的和可验证的例子,给你(谢谢 Stephen Ball):

library ADelphiDLL;

uses
System.SysUtils, System.Classes, Threading, SyncObjs;

function IsPrime (N: Integer): Boolean;
var
Test: Integer;
begin
IsPrime := True;
for Test := 2 to N - 1 do
if (N mod Test) = 0 then
begin
IsPrime := False;
break; {jump out of the for loop}
end;
end;

function Prime(Max : integer) : boolean;
var
tot : integer;
begin
tot := 0;
TParallel.For(1, Max, procedure (I: Integer)
begin
if IsPrime (I) then
TInterlocked.Increment (Tot);
end);
return true;
end;

exports Prime;

begin
IsMultiThread := True;
end.

在 C++ 中:

#include "stdafx.h"

typedef bool(__stdcall *primesf)(int);

void main()
{
HINSTANCE hGetDLL = LoadLibrary(L"ADelphiDLL.dll");
primesf primes = (primesf)GetProcAddress(hGetProcIDDLL, "Primes");
bool result = primes(100);
FreeLibrary(hGetDLL);// <-- Hangs here forever
}

针对非常“有帮助”的评论,“代码中存在缺陷”和“自己调试”,谢谢,这是我已经做了很长时间的事情。因此,如果这里没有任何帮助,我将尝试获得切换到 OTL 的许可,它在相关 DLL 中确实有效。

更新 2

OTL 完全按照预期工作。所以,是的,有一个“代码缺陷”。我放弃。我会建议完全放弃 Delphi,然后我们可以将所有内容转移到 C++ 和 C#。这必须是一个更好的短期(和长期)解决方案。

最佳答案

虽然我使用的是 Delphi 10.0 Seattle 和加载 Delphi DLL 的 Delphi EXE,但我看到了与此类似的问题。

无论如何,我想出的解决方案如下:

  1. 在您的 Delphi DLL 中,首先创建您自己的线程池。

  2. 使用 TParallel 的重载版本。For 将线程池对象作为其最后一个参数,并提供您自己的线程池对象。

  3. 在卸载您的 Delphi DLL 之前,确保释放您的线程池对象。

这种方法解决了我的问题。

TParallel.For documentation:

http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Threading.TParallel.For

示例伪代码:

MyPool: TThreadPool;
MyPool := TThreadPool.Create;

TParallel.For(1, Max, procedure (I: Integer)
begin
if IsPrime (I) then
TInterlocked.Increment (Tot);
end,
MyPool
);

MyPool.Free;

关于c++ - 调用 FreeLibrary 时可能出现死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43536523/

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