-
Вопрос знатокам WinAPI (и желательно POSIX)
В произвольное время разные потоки дёргают мою функцию. Причём потоки могут быть созданы в отдельном Dll кем угодно.
В момент вызова функции я могу получить CurretThreadId.
Необходимо, зная эти ThreadId, навесить на потоки какой-нибудь калбек, который будет вызываться после завершения потока. С эксепшном или в штатном режиме.
Каким образом?
Опережая вопрос "зачем тебе это".
Есть несколько мультипоточных высоконагруженных проектов. Причём бывает потоки создаются в сторонней Dll.
Было решено поменять принципы обработки данных, задействуя threadvar и кеширование данных/буферов.
Но беда в том, что threadvar-области не финализируются при завершении потока.
Тот же TParallel постоянно создаёт и удаляет потоки, а у нас течёт память, причём серьёзно.
-
Вешаешь Хук на EndThread
-
Как?
Сработает ли это на потоки, которые созданы вне Delphi?
-
Создаешь свой поток-следилку и там делаешь:
OpenThread+WaitForSingleObject.
Чтобы следить сразу за несколькими потоками: WaitForMultipleObjects и алгоритм посложнее. Тут можно добавить еще Event, чтобы можно было прерывать WaitForMultipleObjects и обновлять список слежения.
Чтобы следить за более чем MAXIMUM_WAIT_OBJECTS потоками, необходимо создать несколько потоков-следилок.
-
> DayGaykin © (17.05.16 21:43) [3]
Такой подход наверное тоже некорректен.
Калбек по идее должен вызываться в завершающемся потоке. Потому что нужен доступ к TLS.
В предложенном тобой варианте - я его не увижу.
-
DLL_THREAD_DETACH
> который будет вызываться после завершения потокав том же потоке.
-
> NoUser © (18.05.16 00:03) [5]
Но у меня же не Dll
Точнее не обязательно Dll
-
PS.
> Было решено поменять принципы обработки
А если у потока после работы с функцией еще много планов на дальнейшую жизнь, то 'ваша' память будет ему в подарок?
-
> Но у меня же не Dll
ну, добавьте ещё и dll
-
> Crysis © (17.05.16 22:39) [4]
> > DayGaykin © (17.05.16 21:43) [3]
>
> Такой подход наверное тоже некорректен.
> Калбек по идее должен вызываться в завершающемся потоке.
> Потому что нужен доступ к TLS.
> В предложенном тобой варианте - я его не увижу.
Тогда нормально никак.
Можно, конечно извратиться так:
Перехватываешь createthread своего процесса. Вместо точки входа указываешь свою функцию, которая: навесит SEH фрейм и перейдет по исходной точке входа. А дальше должно быть понятно, если знать что такое SEH фрейм.
-
> А если у потока после работы с функцией еще много планов
> на дальнейшую жизнь, то 'ваша' память будет ему в подарок?
В том то и дело
"В подарок" только на время работы. А по завершению потока - память надо грамотно забрать.
-
> Перехватываешь createthread своего процесса. Вместо точки
> входа указываешь свою функцию, которая: навесит SEH фрейм
> и перейдет по исходной точке входа. А дальше должно быть
> понятно, если знать что такое SEH фрейм.
Тогда уж не CreateThread, а ExitThread
Но я боюсь, Касперский заблокирует наш софт у клиентов. Или иные антивирусы будут ругаться.
-
> Crysis © (18.05.16 00:30) [11]
В ExitThread может и не настать.
> Но я боюсь, Касперский заблокирует наш софт у клиентов.
> Или иные антивирусы будут ругаться.
В своем процессе ты можешь делать что хочешь.
-
Тогда лучше ZwCreateThread перехватить и там свою потоковую процедуру с SEH.
-
> Crysis © (17.05.16 16:43)
> Причём бывает потоки создаются в сторонней Dll.Было решено
> поменять принципы обработки данных, задействуя threadvar
> и кеширование данных/буферов.Но беда в том, что threadvar-
> области не финализируются при завершении потока.
threadvar - здесь костыль.
Если какому-либо потоку нужны приватные данные, то он может
распределить память и передать твоей функции указатель на нее.
Перед завершением работы он должен ее освободить.
В случае если код потоков менять нельзя, то память для
потоков может выделять твоя функция, при условии, что
один (или более поток) приложения будет следить путем
WaitForMultipleObjects за рабочими и по их завершении
освобождать связанную с ними память.
Про синхронизацию доступа к общим ресурсам промолчу,
бо, с этим, наверное, все в порядке.
--
Regards, LVT.
-
> Leonid Troyanovsky © (18.05.16 13:27) [14]
> будет следить путем WaitForMultipleObjects за рабочими и
> по их завершении освобождать связанную с ними память.
Схему можно упростить до следующей:
Функция ведет список (ThreadList) троек: ThreadId,
OTHandle(хендл OpenThread),
Data(указ. на распред. память).
Когда список (или память) переполнится, проходим по списку,
проверяем состояние OTHandle (f.e., GetThreadExitCode),
утилизируем память, CloseHandle, удаляем лишнее.
--
Regards, LVT.
-
> Rouse_ © (18.05.16 12:00) [13]
> Тогда лучше ZwCreateThread перехватить и там свою потоковую
> процедуру с SEH.
А можно поподробнее?
Подойдёт ли этот способ для потоков, созданных вне Delphi?
-
> А можно поподробнее?
Лучше расскажи/покажи как это "созданные кем угодно в отдельном Dll" потоки дёргают функцию в твоём exe ?
-
> NoUser © (18.05.16 17:14) [17]
А что удивительного? Передаётся калбек, он вызывает в отдельных потоках.
-
> Передаётся калбек
И что, внутри калбека каждому "новенькому" потоку даруется безвозмездно кусок памяти? - хорошенький "принцип обработки данных" !