Я написал пул потоков с опцией завершения для потоков, доступных пользователю. Как описано в Документация по API terminateThread()
,
Если целевой поток выполняет определенные вызовы kernel32, когда он завершается, состояние kernel32 для процесса потока может быть несовместимым.
Я мог бы сам проверить эту проблему: завершение потока в этом состоянии вызвало проблемы с выделением памяти (среди прочих), но исправление этого условия решило проблемы одновременно.
Вопросы
Итак, я хочу проверять это внутреннее состояние после каждого использования terminateThread()
. Если terminateThread()
вызвало проблему для внутреннего состояния процесса в kernel32.dll, я хочу вызвать исключение - и завершить процесс после регистрации пользователя (если исправление внутреннего состояния все еще возможно).
Это возможно? Может быть, найдя адрес соответствующей переменной состояния (или что-то в этом роде - сопоставив pdb-файл kernel32 или другим способом)? Ситуация плохая для меня - если я не могу решить ее, я должен либо опустить параметр завершения для пула потоков, либо просто оставить поток для себя. Будем благодарны за любые подсказки!
Есть ли какая-либо другая функция win32, которая вызывает аналогичные проблемы?
a. Безопасно ли оставлять поток для себя, когда он вызвал блокирующую функцию kernel32, которая точно никогда не вернется?
b. Что произойдет, если функция win32 вернется и лямбда-функция будет уничтожена?
Почему я спрашиваю это? (Дополнительная информация)
У меня есть собственный поток потоков в моем проекте, где я вызываю некоторые win32 API, которые иногда могут блокироваться навсегда. Следовательно, я звоню им, используя тайм-аут. По истечении этого времени я вызываю terminateThread()
, и мой пул потоков возвращает «неудавшееся состояние вызова».
Иногда мое текущее приложение заходит в тупик. Я обнаружил, что эта тупиковая ситуация происходит в пуле потоков, поэтому я ищу альтернативы terminateThread()
(например, оставляю поток, как я описал в вопросе) или пытаюсь исправить внутреннее состояние или, по крайней мере, проверить, terminateThread()
- это root моего тупика.
Я также хотел бы повторно использовать этот пул потоков в других проектах, поэтому я должен сделать его безопасным.
Обновление: проблема исправлена.
Я обнаружил ошибку в своем приложении: фактически это был вызов terminateThread()
, когда время ожидания в моем пуле потоков уже было мало (около 200 мс). Поток был прерван в момент, когда он не блокировался (то есть, если бы оставался более длительный период ожидания, он работал бы и возвращался правильно). Из трассировки стека ядра я обнаружил, что в режиме ядра мьютекс блокировался, пока поток был прерван, и пока поток выходил, другие потоки уже ждали этого мьютекса.
Сначала возникла проблема до go, увеличив минимальный тайм-аут до 1000 мс, но я не согласился с этим: мое решение состояло в том, чтобы создать лямбда в куче при достижении тайм-аута, оставить лямбду и поток для себя без завершения и добавить это к списку _ToTerminateThreads
. Список завершается один раз в 10 минут (ждет 10 минут, копирует список, ждет еще одну минуту, а затем завершает потоки и удаляет лямбды).
Тем не менее, после тестирования и часов отладки я получал куча искажений. Наконец, я обнаружил следующее: потоки, которые я оставил для удаления, записали в память, которая использовалась пользовательской функцией (которая была передана в пул потоков), - и они были освобождены, потому что поток потоков вернулся. Это вызвало конечные проблемы, поэтому окончательным решением было увеличить время ожидания до безопасного уровня.
Я рекомендую всем, кому нужна такая функция, развернуть ее в дочернем процессе и вместо этого завершить этот процесс. использования темы.
Я держу этот вопрос открытым, потому что на основные 4 вопроса еще не ответили. Для моей проблемы мне больше не нужен их ответ, но они могут быть интересны для других членов stackoverflow.