Muszę napisać DLL w Delphi XE7. Chcę użyć TParallel.For w DLL. Biblioteka DLL jest ładowana do aplikacji C++, w której wszystko działa. Jednak po zakończeniu aplikacji lub po wywołaniu funkcji FreeLibrary aplikacja zawiesza się. Jeśli usunę wszystkie pętle TParallel.For i zastąpię je standardowymi pętlami, aplikacja zakończy działanie normalnie.Możliwy zakleszczenie przy wywołaniu FreeLibrary
TParallel.For pętle są bardzo proste:
TParallel.For(0, inImage.Height -1,
Procedure(ty : integer)
begin
SomeProcedure(ty);
end);
Jeśli utworzyć aplikację Delphi z dokładnie tego samego kodu, wszystko działa idealnie.
Po przeprowadzeniu wielu badań i debugowaniu wygląda na to, że istnieje zakleszczenie, które uniemożliwia wyjście aplikacji C++ po wywołaniu FreeLibrary, ale nie mogę znaleźć miejsca, w którym problem występuje w trybie TParallel.
Wystarczy, aby podsumować sytuację:
- TParallel.For pętle produkować wszystko kompletne i poprawne wyniki.
- Dokładnie ten sam kod TParallel.For w Delphi .exe działa poprawnie.
- Biblioteka DLL jest ładowana, a funkcje są wywoływane i poprawnie wykonywane z poziomu aplikacji C++.
- Aplikacja C++ zakończy poprawnie, jeśli nie ma połączenia TParallel.For.
- Aplikacja C++ zawiesza się, jeśli istnieją TParallel.For.
- Zgaduję, że istnieje zakleszczenie, które występuje, gdy wywoływana jest FreeLibrary.
- Jeśli korzystam z biblioteki wątków OTL, wszystko działa tak, jak powinno.
Moje pytania są następujące:
Czy ktoś doświadczył tego zachowania?
Jaka jest dobra strategia debugowania w celu znalezienia impasu w tej sytuacji?
Każda rada jest bardzo doceniana.
UPDATE
OK, więc jeśli chcesz, Minimal, kompletne i weryfikowalne przykład, tutaj idziesz (dziękuję 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.
w 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
}
W odpowiedź na bardzo "pomocne" komentarze, "jest defekt w kodzie" i "debugowanie go samemu", dziękuję, to jest to, co robiłem przez zbyt długi czas. Tak więc, jeśli nie ma tu żadnej pomocy, postaram się uzyskać pozwolenie na przejście na OTL, które działa w danej bibliotece DLL.
UPDATE 2
OTL działa dokładnie tak, jak oczekiwano. Tak, tak, istnieje "defekt w kodzie". Poddaję się. Zalecam całkowite zrezygnowanie z Delphi, a następnie możemy przenieść wszystko do C++ i C#. To musi być znacznie lepsze rozwiązanie krótko (i długoterminowe).
Podejrzewam, że 'TParallel' tworzy puli wątków i wymaga wyraźnej porządki, aby zatrzymać im. Plik wykonywalny Delphi jest świadomy tego zachowania i wykonuje czyszczenie, podczas gdy plik wykonywalny C++ tego nie robi. – VTT
W kodzie jest wada. Tylko ty masz kod. Bez [mcve] możemy tylko zgadywać. Nie każ nam zgadywać. Albo wytworzą [mcve], albo zrobisz trochę debugowania. –
Nie trzeba się poddawać i obwiniać ludzi, którzy próbują pomóc. Wygląda na to, że masz dobrego kandydata na raport QP. Zrób to, a także dołącz do grupy deweloperów G + Delphi i zgłoś to tam. David M jest tam aktywny i może pomóc. –