2017-04-21 4 views
10

Ich muss eine DLL in Delphi XE7 schreiben. Ich möchte TParallel.For in der DLL verwenden. Die DLL wird in eine C++ - Anwendung geladen, wo alles funktioniert. Wenn die Anwendung jedoch beendet wird oder ein Aufruf von FreeLibrary erfolgt, hängt die Anwendung. Wenn ich alle TParallel.For-Schleifen lösche und sie durch Standardschleifen ersetze, wird die Anwendung normal beendet.Möglicher Deadlock beim Aufruf von FreeLibrary

Die TParallel.For Schleifen sind sehr einfach:

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

Wenn ich eine Delphi-Anwendung mit genau dem gleichen Code zu erstellen, alles perfekt funktioniert.

Nach viel Forschung und Debugging sieht es aus wie ein Deadlock, der verhindert, dass die C++ Anwendung beendet wird, wenn FreeLibrary aufgerufen wird, aber ich kann nicht finden, wo das Problem in TParallel ist.

einfach die Situation zusammenfassen:

  • Die TParallel.For alle kompletten Loops und die richtigen Ergebnisse erzielen.
  • Derselbe TParallel.For-Code in einer Delphi-.exe funktioniert ordnungsgemäß.
  • Die DLL wird geladen, und die Funktionen werden ordnungsgemäß in der C++ - Anwendung aufgerufen und ausgeführt.
  • Die C++ - Anwendung wird ordnungsgemäß beendet, wenn keine TParallel.For-Schleifen vorhanden sind.
  • Die C++ - Anwendung wird hängen, wenn TParallel.For-Schleifen vorhanden sind.
  • Ich vermute, dass es einen Deadlock gibt, der auftritt, wenn FreeLibrary aufgerufen wird.
  • Wenn ich die OTL-Threading-Bibliothek verwende, funktioniert alles wie es sollte.

Meine Fragen sind:

Hat jemand anderes dieses Verhalten erlebt?

Was ist eine gute Debugging-Strategie, um in dieser Situation einen Deadlock zu finden?

Jeder Rat wird sehr geschätzt.

UPDATE

OK, wenn Sie also Minimal, vollständig und überprüfbar Beispiel wollen, hier gehen Sie (danke 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. 

in 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 
} 

In Antwort auf die sehr "hilfreiche" Kommentare, "es gibt einen Defekt im Code" und "debug es selbst", danke, das ist, was ich schon zu lange gemacht habe. Also, wenn es hier keine Hilfe gibt, werde ich versuchen, die Erlaubnis zu bekommen, zu OTL zu wechseln, was in der fraglichen DLL funktioniert.

UPDATE 2

OTL funktioniert genau wie erwartet. Also, ja, es gibt einen "Defekt im Code". Ich gebe auf. Ich werde empfehlen, Delphi ganz aufzugeben und dann können wir alles nach C++ und C# verschieben. Das muss eine viel bessere kurze (und langfristige) Lösung sein.

+2

Ich vermute, dass 'TParallel' einen Pool Thread erstellt und erfordert einige explizite Bereinigung zu stoppen Sie. Die ausführbare Datei von Delphi erkennt dieses Verhalten und führt eine Bereinigung durch, während die ausführbare Datei von C++ dies nicht tut. – VTT

+0

Es gibt einen Fehler im Code. Nur du hast den Code. Ohne ein [mcve] können wir nur raten. Lass uns nicht raten. Entweder produzieren Sie ein [mcve] oder führen Sie selbst ein Debugging durch. –

+2

Kein Grund aufzugeben und Leuten die Schuld zu geben, die versuchen zu helfen. Es scheint, dass Sie einen guten Kandidaten für einen QP-Bericht haben. Bitte machen Sie das und treten Sie auch der g + Delphi Developers Gruppe bei und melden Sie sie dort. David M ist dort aktiv und kann helfen. –

Antwort

3

Ich habe ein ähnliches Problem gesehen, obwohl ich Delphi 10.0 Seattle und eine Delphi-EXE verwendet habe, die eine Delphi-DLL geladen hat.

Wie auch immer, die Lösung, die ich mit aufkommen ist der folgende:

  1. In Delphi DLL zunächst Ihren eigenen Thread-Pool erstellen.

  2. Verwenden Sie die überladene Version von TParallel.For, die ein Thread-Pool-Objekt als letzten Parameter verwendet und ein eigenes Thread-Pool-Objekt bereitstellt.

  3. Bevor Sie Ihre Delphi-DLL entladen, stellen Sie sicher, dass Sie Ihr Thread-Pool-Objekt freigeben.

Dieser Ansatz löste das Problem für mich.

TParallel.For Dokumentation:

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

Beispiel Pseudocode:

MyPool: TThreadPool; 
MyPool := TThreadPool.Create; 

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

MyPool.Free; 
Verwandte Themen