Использую стороннюю dll в многопоточном режиме. Эта dll создает свои потоки и делает из них callback вызовы в мой код. Хочется узнать, в каком моем потоке был создан поток в dll. Единственная моя идея — перехватывать CreateThread/ExitThread и самостоятельно ручками строить дерево потоков и анализировать его в callback функциях. Может быть есть более нативный метод?
Здравствуйте, Aniskin, Вы писали:
A>Использую стороннюю dll в многопоточном режиме. Эта dll создает свои потоки и делает из них callback вызовы в мой код. Хочется узнать, в каком моем потоке был создан поток в dll. Единственная моя идея — перехватывать CreateThread/ExitThread и самостоятельно ручками строить дерево потоков и анализировать его в callback функциях. Может быть есть более нативный метод?
Скорее всего нет. В CreateThread никакой информации о текущем потоке никуда не передаётся. Но лучше посмотреть в исходники, может это и не так
Здравствуйте, Aniskin, Вы писали:
A>Использую стороннюю dll в многопоточном режиме. Эта dll создает свои потоки и делает из них callback вызовы в мой код. Хочется узнать, в каком моем потоке был создан поток в dll. Единственная моя идея — перехватывать CreateThread/ExitThread и самостоятельно ручками строить дерево потоков и анализировать его в callback функциях. Может быть есть более нативный метод?
Хм, а какую проблему позволило бы решить знание графа потоков?
В принципе, если гарантировать, что одновременно только один свой поток работает с той DLL одновременно, и Id этого потока записан в какой-то своей глобальной переменной, то, получив DLL_THREAD_ATTACH TLS-нотификацию, можно записать Id своего потока в TLS для DLL потока.
Здравствуйте, Alexander G, Вы писали:
AG>Хм, а какую проблему позволило бы решить знание графа потоков?
Грубо говоря, я перехватываю в dll CreateFileW и мне нужно понять контекст текущей операции.
AG>В принципе, если гарантировать, что одновременно только один свой поток работает с той DLL одновременно
Как я написал в исходном сообщении, я использую стороннюю dll в многопоточном режиме.
Здравствуйте, Aniskin, Вы писали:
A>Использую стороннюю dll в многопоточном режиме. Эта dll создает свои потоки и делает из них callback вызовы в мой код. Хочется узнать, в каком моем потоке был создан поток в dll. Единственная моя идея — перехватывать CreateThread/ExitThread и самостоятельно ручками строить дерево потоков и анализировать его в callback функциях. Может быть есть более нативный метод?
Несколько странное желание, почему бы не хранить threadId стартовавшего потока в контексте операции?
Каждый, просыпаясь утром, должен задавать себе вопрос — что он может сегодня сделать, чтобы россиянства
Здравствуйте, Aniskin, Вы писали:
AG>>Хм, а какую проблему позволило бы решить знание графа потоков?
A>Грубо говоря, я перехватываю в dll CreateFileW и мне нужно понять контекст текущей операции.
Ясно, ну тогда может такой граф и поможет. А может и нет, если dll на самом деле использует тредпул и разные операции в том же её потоке.
За контекст вроде имени файла там точно нельзя зацепиться?
A>Использую стороннюю dll в многопоточном режиме. Эта dll создает свои потоки и делает из них callback вызовы в мой код. Хочется узнать, в каком моем потоке был создан поток в dll. Единственная моя идея — перехватывать CreateThread/ExitThread и самостоятельно ручками строить дерево потоков и анализировать его в callback функциях. Может быть есть более нативный метод?
ExitThread хукать необязательно, можно просто открывать (дублицировать в себя) и ждать контролируемые потоки (RegisterWaitForSingleObject прям так и напрашивается)
Как много веселых ребят, и все делают велосипед...
Здравствуйте, mjau, Вы писали:
M>Здравствуйте, Aniskin, Вы писали:
A>>Использую стороннюю dll в многопоточном режиме. Эта dll создает свои потоки и делает из них callback вызовы в мой код. Хочется узнать, в каком моем потоке был создан поток в dll. Единственная моя идея — перехватывать CreateThread/ExitThread и самостоятельно ручками строить дерево потоков и анализировать его в callback функциях. Может быть есть более нативный метод?
M>Несколько странное желание, почему бы не хранить threadId стартовавшего потока в контексте операции?
Не совсем понял твой комментарий. Где и что хранить?
Вот запустил я N потоков, каждый из которых выполняет операцию OpN с использованием dll. Dll для каждой операции создает дополнительный поток, из которого вызывает некую callback функцию. В параметрах callback функции нет параметра, позволяющего мне идентифицировать мой исходный поток. Как мне его определить?
Здравствуйте, Alexander G, Вы писали:
AG>За контекст вроде имени файла там точно нельзя зацепиться?
Нет, там очень общие функции. Типа ErrorHappens(Msg), и я должен знать, является ли операция, к которой относится этот callback вызов, silent или же я все же могу показать окно с ошибкой. Это просто пример, но суть примерно такая.
M>>Несколько странное желание, почему бы не хранить threadId стартовавшего потока в контексте операции?
A>Вот запустил я N потоков, каждый из которых выполняет операцию OpN с использованием dll. Dll для каждой операции создает дополнительный поток, из которого вызывает некую callback функцию. В параметрах callback функции нет параметра, позволяющего мне идентифицировать мой исходный поток. Как мне его определить?
А как вы определяете, к какой операции относится колбек?
Или длл строго однопоточная и одна операция происходит в один момент времени? В таком случае, идеологически правильно было бы завернуть dll в отдельный процесс для исключения разных веселых проблем с однопоточной dll в многопоточной среде.
В случае же одного процесса нет стандартных средств получить родителя потока, т.к. потоки не имеют иерархии, тут либо городить велосипеды, либо как вариант покопаться в TEB, но вероятность того, что там будет что-то подходящее, весьма мала.
Каждый, просыпаясь утром, должен задавать себе вопрос — что он может сегодня сделать, чтобы россиянства
Здравствуйте, ononim, Вы писали:
O>ExitThread хукать необязательно, можно просто открывать (дублицировать в себя) и ждать контролируемые потоки (RegisterWaitForSingleObject прям так и напрашивается)
Для отслеживания завершения потока достаточно контроля через DLL_THREAD_DETACH из DllMain либо TLS Callback, наверное
Решение на ожиданиях гипотетически подвержено гонке: поток уже завершился, и может быть новый поток с таким ID (практически нет, recycle там долгий).
Но зато оно справится с TerminateThread или прямым NtTerminateThread ( для психов, готовых поддерживать такие сценарии ).
O>>ExitThread хукать необязательно, можно просто открывать (дублицировать в себя) и ждать контролируемые потоки (RegisterWaitForSingleObject прям так и напрашивается) AG>Для отслеживания завершения потока достаточно контроля через DLL_THREAD_DETACH из DllMain либо TLS Callback, наверное
топикстартер не говорил что у него под рукой еще и своя длл есть. Впрочем FlsCallback()-у она не нужна
AG>Решение на ожиданиях гипотетически подвержено гонке: поток уже завершился, и может быть новый поток с таким ID (практически нет, recycle там долгий).
Нет. Пока есть хоть один незакрытый хэндл на поток, его ID не переюзают.
AG>Но зато оно справится с TerminateThread или прямым NtTerminateThread ( для психов, готовых поддерживать такие сценарии ).
Да
Как много веселых ребят, и все делают велосипед...
Здравствуйте, mjau, Вы писали:
M>Как можно позволить работу в многопоточном режиме без предоставления механизма связи запроса и ответа ?
Сценарии бывают всякие разные. Одно из моих действий — перехват CreateFile и еще пары функций в dll. А в операции я не знаю, что будет передано в CreateFile.
AG>>Хм, а какую проблему позволило бы решить знание графа потоков? A>Грубо говоря, я перехватываю в dll CreateFileW и мне нужно понять контекст текущей операции.
Хреновая какаято архитектура. А если автор длл заюзал/решит заюзать thread pool?
Как много веселых ребят, и все делают велосипед...
Здравствуйте, ononim, Вы писали:
O>Хреновая какаято архитектура.
Суть одной из проблем более детально — я в своей поделке TC4Shell использую (в том числе) стороннюю библиотеку unrar.dll для распаковки rar архивов. Грубо говоря я указываю ей "распакуй некоторые файлы в такую то директорию, которую выбрал пользователь". Соответственно, если пользователь выбрал, например, директорию Program Files, то при распаковке произойдет ERROR_ACCESS_DENIED, а мне вернется какой нибудь внутренний ERAR_ECREATE. А я хочу в этой ситуации спросить пользователя, не хочет ли он повысить права до админа (недавно создавал топик об этом). Если пользователь захочет, то повышаем, и вызываем CreateFile с админовыми правами. Но что бы это реализовать мне нужно перехватывать CreateFile. В тоже время ряд операций типа извлечения эскиза файла в Проводнике должны быть тихими без всякого UI. Это один из сценариев.
O>А если автор длл заюзал/решит заюзать thread pool?
Будет обидно и придется отказаться от своей затеи.
A>Суть одной из проблем более детально — я в своей поделке TC4Shell использую (в том числе) стороннюю библиотеку unrar.dll для распаковки rar архивов. Грубо говоря я указываю ей "распакуй некоторые файлы в такую то директорию, которую выбрал пользователь". Соответственно, если пользователь выбрал, например, директорию Program Files, то при распаковке произойдет ERROR_ACCESS_DENIED, а мне вернется какой нибудь внутренний ERAR_ECREATE. А я хочу в этой ситуации спросить пользователя, не хочет ли он повысить права до админа (недавно создавал топик об этом). Если пользователь захочет, то повышаем, и вызываем CreateFile с админовыми правами. Но что бы это реализовать мне нужно перехватывать CreateFile. В тоже время ряд операций типа извлечения эскиза файла в Проводнике должны быть тихими без всякого UI. Это один из сценариев.
Я бы вынес все это дело в отдельный процесс. Если бы встал вопрос перфоманса изза задержки на его запуск — сделал бы этот процесс воркером, издыхающим только когда сдохнет его хозяин. Как вариант — COM сервер-ом.
Как много веселых ребят, и все делают велосипед...