Как я могу установить свой собственный тайм-аут?
-
22-08-2019 - |
Вопрос
Мне приходится использовать API для вызова третьей стороны и в идеале использовать возвращаемый ею ответ.API имеет встроенный 30-секундный тайм-аут и не позволяет установить его программно.Мне нужно, чтобы время ожидания истекло через 12 секунд.Вот звонок, который я делаю:
строковый ответ = theAPI.FunctionA(a, b, c, d);
Я подумал, что для этого мне, возможно, придется использовать асинхронные вызовы и прервать поток через 12 секунд.Другой вопрос о stackoverflow, похоже, близок к тому, что я рассматриваю: Реализация общего тайм-аута C#
...Мне просто интересно, лучший ли это способ.В частности, я продолжаю видеть статьи, в которых предупреждают вас о необходимости вызова EndInvoke, несмотря ни на что, и мне интересно, будет ли Abort, как в приведенном примере, правильно закрывать поток?Я вижу, что были некоторые комментарии с большой озабоченностью по поводу использования Abort.
Решение
Прерывание потоков, как правило, является плохой идеей.Почему бы просто не позволить вызову завершиться (или истечь по истечении 30 секунд), но проигнорировать результат (и двигаться дальше), если он занимает более 12 секунд?
Другие советы
Thread.Abort
конечно, закроет тему, так как вызовет Win32 TerminateThread
.
Результат этого действия будет зависеть от того, насколько ваш API
любит, когда его закрывают TerminateThread
.
Если ваш метод называется что-то вроде NuclearPlant.MoveRod()
или Defibrillator.Shock()
, я лучше подожду эти 30 секунд.
Этот метод не дает жертве возможности выполнить какую-либо очистку:
TerminateThread
используется для завершения потока.Когда это происходит, целевой поток не имеет возможности выполнить какой-либо код пользовательского режима.Библиотеки DLL, прикрепленные к потоку, не уведомляются о завершении потока.Система освобождает начальный стек потока.
Как сказано в MSDN
:
TerminateThread
— опасная функция, которую следует использовать только в самых крайних случаях.Вам следует позвонитьTerminateThread
только если вы точно знаете, что делает целевой поток, и контролируете весь код, который целевой поток может выполнять в момент завершения.Например,TerminateThread
может привести к следующим проблемам:
- Если целевой поток владеет критическим разделом, этот критический раздел не будет освобожден.
- Если целевой поток выделяет память из кучи, блокировка кучи не будет снята.
- Если целевой поток выполняет определенные вызовы kernel32, когда он завершается, состояние kernel32 для процесса потока может быть противоречивым.
- Если целевой поток манипулирует глобальным состоянием общей DLL, состояние DLL может быть уничтожено, что повлияет на других пользователей DLL.