Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Ошибка освобождения библиотек в пуле потоков Delphi 11: исправление TThreadPool.Destroy

Delphi , Компоненты и Классы , Потоки

 

В последних версиях Delphi 11 Update 3 была внесена поправка в реализацию библиотеки RTL (Run-Time Library) для устранения проблемы, связанной с освобождением библиотек в пуле потоков (TThreadPool). Однако эта поправка не всегда работает корректно, особенно при использовании BPL-построения. В этой статье мы рассмотрим проблему, её причину и предложим несколько решений.

Проблема

Основная проблема заключается в том, что уничтлажение объекта TThreadPool сталкивается с ограничениями, связанными с функцией FreeLibrary. В частности, если библиотека загружается и затем выгружается, приложение может зависнуть на этапе вызова FreeLibrary(). Это происходит из-за того, что метод TThreadPool.Destroy не всегда корректно обрабатывает ситуацию выгрузки библиотеки.

Пример кода, который демонстрирует проблему:

program ThreadPool;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Winapi.Windows,
  System.Threading;

procedure DoSomeTasksFromDll();
var
  lHandle: Cardinal;
  lProc : procedure;
begin
  Writeln('Calling LoadLibrary()');
  lHandle := LoadLibrary('threadlib.dll');
  Writeln('LoadLibrary() = ', lHandle);

  Writeln('Calling GetProcAddress()');
  lProc := GetProcAddress(lHandle, 'DoSomeTasks');
  Writeln('GetProcAddress() = ', NativeInt(@lProc));

  Writeln('Calling DoSomeTasks()');
  lProc();
  WriteLn('DoSomeTasks() done');

  WriteLn('Calling FreeLibrary()');
  FreeLibrary(lHandle); // App will freeze here forever 
  WriteLn('FreeLibrary() done');
end;

begin
  try
    // Has no effect :(
    System.IsLibrary := true;
    WriteLn('System.IsLibrary: ', System.IsLibrary);

    WriteLn('Current thread: ', GetCurrentThreadId());
    DoSomeTasksFromDll();
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

  Writeln('Any key pls');
  readln;
end.

Причина проблемы

В методе TThreadPool.Destroy используется флаг IsDLLDetaching, который должен быть установлен в случае выгрузки библиотеки. Однако, если библиотека загружается и выгружается, флаг IsLibrary может быть установлен неправильно, что приводит к зависанию приложения на этапе вызова FreeLibrary().

Решение

Для устранения этой проблемы можно использовать несколько подходов:

Использование собственного DllProc

Один из способов решения проблемы - это использование собственного обработчика событий DLL (DllProc). Этот обработчик должен быть правильно цепочкой к стандартному обработчику RTL, чтобы обеспечить корректное освобождение библиотеки. Пример:

program ThreadPool;

{$APPTYPE CONSOLE}

{$R *.res}

uses System.SysUtils, Winapi.Windows, System.Threading;

var OldDllProc: TFarProc;

function MyDllProc(dwReason: DWord): Bool; stdcall;
begin
Result := True;
if dwReason = DLL_PROCESS_DETACH then
begin
// Ваш код для освобождения ресурсов
end;
end;

procedure SetCustomDllProc;
begin
OldDllProc := GetProcAddress(GetModuleHandle('rtl.bpl'), 'DLLProc');
if Assigned(OldDllProc) then
begin
SetDLLProc(@MyDllProc);
end;
end;

procedure DoSomeTasksFromDll();
var lHandle: Cardinal;
lProc : procedure;
begin
Writeln('Calling LoadLibrary()');
lHandle := LoadLibrary('threadlib.dll');
Writeln('LoadLibrary() = ', lHandle);

 Writeln('Calling GetProcAddress()');
 lProc := GetProcAddress(lHandle, 'DoSomeTasks');
 Writeln('GetProcAddress() = ', NativeInt(@lProc));

 Writeln('Calling DoSomeTasks()');
 lProc();
 WriteLn('DoSomeTasks() done');

 WriteLn('Calling FreeLibrary()');
 FreeLibrary(lHandle); // App will freeze here forever 
 WriteLn('FreeLibrary() done');

end;

begin try SetCustomDllProc; WriteLn('System.IsLibrary: ', System.IsLibrary);

   WriteLn('Current thread: ', GetCurrentThreadId());
   DoSomeTasksFromDll();
 except
   on E: Exception do
     Writeln(E.ClassName, ': ', E.Message);
 end;

 Writeln('Any key pls');
 readln;

end. ```

Использование патчей или обновлений от Embarcadero

Если проблема связана с багом в RTL, то можно ожидать, что Embarcadero выпустит обновление, которое исправит эту проблему. В этом случае лучше всего будет дождаться официального обновления и использовать его.

Избегание использования TThreadPool в DLL

Если проблема не может быть решена, можно рассмотреть возможность избегания использования TThreadPool в DLL. Вместо этого можно использовать другие механизмы управления потоками, которые не зависят от RTL.

Заключение

Проблема с освобождением библиотеки в пуле потоков в Delphi 11 Update 3 может быть решена с помощью использования собственного обработчика событий DLL или ожидания официального обновления от Embarcadero. Важно помнить, что использование собственного обработчика событий DLL требует тщательной настройки и тестирования, чтобы избежать других проблем с управлением ресурсами.

Надеюсь, что эта статья поможет вам решить проблему с освобождением библиотеки в пуле потоков в Delphi 11 Update 3. Если у вас есть дополнительные вопросы или предложения, пожалуйста, не стесняйтесь задавать их в комментариях.

Создано по материалам из источника по ссылке.

В Delphi 11 Update 3 обнаружена проблема с корректным освобождением библиотек в пуле потоков (TThreadPool), особенно при использовании BPL-построения, приводящая к зависанию приложения при вызове FreeLibrary().


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Потоки ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-04-23 04:47:16/0.0035738945007324/0