Мне нужно написать DLL в Delphi XE7. Я хочу использовать TParallel.For в DLL. DLL загружается в приложение С++, где все работает. Однако, когда приложение завершается или выполняется вызов FreeLibrary, приложение зависает. Если я удалю все петли TParallel.For и заменим их стандартными циклами, приложение нормально завершится.
Циклы TParallel.For очень просты:
TParallel.For(0, inImage.Height -1,
Procedure(ty : integer)
begin
SomeProcedure(ty);
end);
Если я создаю приложение Delphi с точно таким же кодом, все работает отлично.
После много исследований и отладки, похоже, что существует тупиковая ситуация, которая препятствует выходу приложения С++ при вызове FreeLibrary, но я не могу найти, где проблема в TParallel.
Просто подведем итог ситуации:
- TParallel.For полностью завершает и производит правильные результаты.
- Точно такой же TParallel.For код в Delphi.exe работает правильно.
- DLL загружается и функции вызываются и выполняются корректно из приложения С++.
- Приложение С++ выйдет правильно, если нет циклов TParallel.For.
- Приложение С++ будет висеть, если есть петли TParallel.For.
- Я предполагаю, что существует тупик, который возникает при вызове 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.
в С++:
#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, и тогда мы сможем переместить все на С++ и С#. Это должно быть гораздо более короткое (и долгосрочное) решение.