c++ - Posible punto muerto en la llamada a FreeLibrary
delphi dll (1)
He visto un problema similar a esto, aunque estaba usando Delphi 10.0 Seattle y un EXE de Delphi cargando una DLL de Delphi.
De todos modos, la solución que se me ocurrió es la siguiente:
En su DLL de Delphi, primero cree su propio grupo de subprocesos.
Utilice la versión sobrecargada de TParallel. Para eso, toma un objeto de grupo de subprocesos como último parámetro y proporcione su propio objeto de grupo de subprocesos.
Antes de descargar su DLL de Delphi, asegúrese de liberar su objeto de grupo de subprocesos.
Este enfoque resolvió el problema para mí.
T Paralelo.Para la documentación:
http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Threading.TParallel.For
Ejemplo de pseudo-código:
MyPool: TThreadPool;
MyPool := TThreadPool.Create;
TParallel.For(1, Max, procedure (I: Integer)
begin
if IsPrime (I) then
TInterlocked.Increment (Tot);
end,
MyPool
);
MyPool.Free;
Tengo que escribir una DLL en Delphi XE7. Quiero usar TParallel.For en la DLL. La DLL se carga en una aplicación C ++, donde todo funciona. Sin embargo, cuando la aplicación finaliza o se realiza una llamada a FreeLibrary, la aplicación se cuelga. Si elimino todos los bucles TParallel.For y los reemplazo con bucles estándar, la aplicación sale normalmente.
Los bucles TParallel.For son muy simples:
TParallel.For(0, inImage.Height -1,
Procedure(ty : integer)
begin
SomeProcedure(ty);
end);
Si creo una aplicación Delphi con exactamente el mismo código, todo funciona perfectamente.
Después de investigar y depurar, parece que hay un punto muerto que impide que la aplicación C ++ salga cuando se llama a FreeLibrary, pero no puedo encontrar dónde está el problema en TParallel.
Solo para resumir la situación:
- El TParallel.For bucles todo completo y produce los resultados correctos.
- El mismo TParallel.For exacto en un Delphi .exe funciona correctamente.
- La DLL se carga y las funciones se llaman y funcionan correctamente desde dentro de la aplicación C ++.
- La aplicación C ++ saldrá correctamente si no hay TParallel.For loops.
- La aplicación C ++ se bloqueará si hay TParallel.For loops.
- Supongo que hay un punto muerto que ocurre cuando se llama a FreeLibrary.
- Si utilizo la biblioteca de threads OTL, todo funciona como debería.
Mis preguntas son:
¿Alguien más ha experimentado este comportamiento?
¿Cuál es una buena estrategia de depuración para encontrar un punto muerto en esta situación?
Cualquier consejo es muy apreciado.
ACTUALIZAR
De acuerdo, si quieres un ejemplo mínimo, completo y verificable, aquí tienes (gracias 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.
en 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
}
En respuesta a los comentarios muy "útiles", "hay un defecto en el código" y "depúralo tú mismo", gracias, eso es lo que he estado haciendo durante demasiado tiempo. Entonces, si no hay ayuda de aquí, intentaré obtener permiso para cambiar a OTL, que funciona en la DLL en cuestión.
ACTUALIZACIÓN 2
OTL funciona exactamente como se esperaba. Entonces, sí, hay un "defecto en el código". Me doy por vencido. Recomendaré abandonar por completo a Delphi y luego podemos pasar todo a C ++ y C #. Esa tiene que ser una solución mucho mejor a corto (y largo plazo).