Разработчики, работающие с многопоточными приложениями в среде Delphi, иногда сталкиваются с проблемой наследования дескрипторов stdout и stderr. При запуске нескольких потоков с помощью функции __CreateProcess__, стандартные потоки вывода могут наследоваться не только теми потоками, для которых это необходимо. В данной статье мы рассмотрим, как можно использовать функции InitializeProcThreadAttributeList и UpdateProcThreadAttribute, а также структуру STARTUPINFOEX для управления наследованием дескрипторов в дочерних процессах.
Проблема наследования дескрипторов
При запуске нескольких процессов в многопоточном приложении, стандартные потоки вывода (stdout и stderr) могут наследоваться всеми запущенными процессами, что может быть нежелательным. Для решения этой проблемы разработчики могут использовать механизмы управления атрибутами потоков, предоставляемые операционной системой Windows.
Использование функций InitializeProcThreadAttributeList и UpdateProcThreadAttribute
Функции InitializeProcThreadAttributeList и UpdateProcThreadAttribute позволяют управлять наследованием дескрипторов в дочерних процессах. Для этого необходимо создать список атрибутов потока и обновить его, указав дескрипторы, которые должны быть переданы дочернему процессу.
Для передачи списка дескрипторов, необходимо создать указатель на массив дескрипторов. В коде разработчика из вопроса было использовано TList<Cardinal>, что привело к ошибкам компиляции, так как ожидается указатель на массив дескрипторов THandle.
type
TStartupInfoEx = record
StartupInfo: TStartupInfo;
lpAttributeList: Pointer;
end;
var
Handles: array of THandle;
StartupInfoEx: TStartupInfoEx;
size: SIZE_T;
begin
// ... инициализация StartupInfoEx ...
Win32Check(not InitializeProcThreadAttributeList(nil, 1, 0, size) and (GetLastError=ERROR_INSUFFICIENT_BUFFER));
GetMem(StartupInfoEx.lpAttributeList, size);
try
Win32Check(InitializeProcThreadAttributeList(StartupInfoEx.lpAttributeList, 1, 0, size));
try
Win32Check(UpdateProcThreadAttribute(
StartupInfoEx.lpAttributeList,
0,
PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
@Handles[0],
Length(Handles) * SizeOf(Handles[0]),
nil,
nil
));
// ... остальной код ...
finally
DeleteProcThreadAttributeList(StartupInfoEx.lpAttributeList);
end;
finally
FreeMem(StartupInfoEx.lpAttributeList);
end;
end;
Важные моменты
Используйте массив дескрипторов THandle для передачи списка дескрипторов.
Убедитесь, что дескрипторы настроены на наследование с помощью SetHandleInformation.
Используйте функции из библиотеки kernel32.dll, так как их определения в стандартном модуле Windows могут быть некорректными.
Подтвержденный ответ
В примере кода выше представлена реализация функции CreateProcessWithInheritedHandles, которая позволяет управлять наследованием дескрипторов. Обратите внимание на правильное использование указателей и размеров данных при работе с функциями InitializeProcThreadAttributeList и UpdateProcThreadAttribute.
Заключение
Использование InitializeProcThreadAttributeList, UpdateProcThreadAttribute и STARTUPINFOEX позволяет разработчикам на Delphi эффективно управлять наследованием дескрипторов в многопоточных приложениях, что особенно важно при работе со стандартными потоками вывода.
Управление наследованием дескрипторов stdout и stderr в многопоточных приложениях на Delphi для корректной работы стандартных потоков вывода в дочерних процессах.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.