問題

私は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アプリケーションを作成すると、すべてが完全に機能します。

多くの研究とデバッグを行った後、FreeLibraryが呼び出されたときにC ++アプリケーションが終了しないようにするデッドロックがあるように見えますが、問題がTParallelのどこにあるのかわかりません。

状況をまとめるだけです:

  • TParallel.Forループはすべて完了し、正しい結果が得られます。
  • Delphi .exeのまったく同じTParallel.Forコードが正しく動作します。
  • DLLがロードされ、関数が呼び出され、C ++アプリケーション内から正しく実行されます。
  • TParallel.Forループがない場合、C ++アプリケーションは正しく終了します。
  • TParallel.Forループがある場合、C ++アプリケーションはハングします。
  • FreeLibraryが呼び出されたときに発生するデッドロックがあると推測しています。
  • OTLスレッドライブラリを使用すると、すべて正常に動作します。

私の質問は次のとおりです:

他の誰かがこの行動を経験しましたか?

この状況でデッドロックを見つけるための良いデバッグ戦略は何ですか?

アドバイスをいただければ幸いです。

更新

Minimal、Complete、およびVerifiableの例が必要な場合は、次のようにします(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
}
 

非常に役に立つ "コメント"に応じて、コードに欠陥があり、 "自分でデバッグする"、ありがとう、それは私が長い間やってきたことです。だから、ここに助けがないなら、私は問題のDLLで動作するOTLに切り替える許可を得ようとします。

更新2

OTLは期待どおりに動作します。したがって、はい、「コードに欠陥があります」。私はあきらめる。私はDelphiを完全に捨てて、すべてをC ++とC#に移動することをお勧めします。それははるかに良い短い(そして長期的な)解決策でなければなりません。

  ベストアンサー

私はDelphi 10.0シアトルと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++delphidll