Как я могу установить свой собственный тайм-аут?

Я должен использовать API для вызова третьей стороны и в идеале использовать возвращаемый ответ. API имеет встроенный 30-секундный тайм-аут и не позволяет вам установить его программно. Мне нужно, чтобы время истекло через 12 секунд. Вот звонок, который я делаю:

строка ответа = theAPI.FunctionA(a, b, c, d);

Я думал, что мне, возможно, придется использовать асинхронные вызовы, чтобы выполнить это и прервать поток через 12 секунд. Другой вопрос stackoverflow, похоже, близок к тому, что я рассматриваю: Реализовать общий тайм-аут C#

... Мне просто интересно, лучший ли это способ. В частности, я продолжаю видеть статьи, которые предупреждают вас о вызове EndInvoke, несмотря ни на что, и мне интересно, будет ли Abort, как в упомянутом примере, по-прежнему правильно закрывать поток? Я вижу, что были некоторые комментарии с большим беспокойством по поводу использования Abort.


person Chad    schedule 10.02.2009    source источник


Ответы (2)


Прерывание потоков, как правило, плохая идея. Почему бы просто не позволить вызову завершиться (или истечь время через 30 секунд), но проигнорировать результат (и двигаться дальше), если он занимает более 12 секунд?

person Jon Skeet    schedule 10.02.2009
comment
Сделка в 12 секунд, мне нужно выручить и двигаться дальше. Я не могу сидеть и ждать целых 30 секунд. Если бы мне разрешили позволить ему работать полные 30 секунд, я бы, конечно, пошел по этому пути. - person Chad; 10.02.2009
comment
Я не предлагал ждать 30 секунд. Обратите внимание на игнорирование результата (и движение дальше), если это занимает более 12 секунд. Все, что я предлагаю, это то, что ваш тайм-аут не должен фактически убивать запрос. Пусть это завершится естественным образом, пока вы занимаетесь другими делами. - person Jon Skeet; 10.02.2009
comment
Хорошо, я думаю, я следую за тобой. Возможно, я бы сделал асинхронный вызов с функцией обратного вызова, ожидающей завершения. Тем временем мой код движется дальше, и если у меня еще нет ответа через 12 секунд, я продолжаю, как если бы был тайм-аут. Моя функция обратного вызова просто ничего не делает, если более 12 секунд. - person Chad; 10.02.2009
comment
Да, что-то в этом роде :) Просто BeginInvoke/WaitOne(timeout)/EndInvoke может быть в порядке, с обратным вызовом, вызывающим EndInvoke, если основной поток этого не делает. Вам нужно будет проверить, что вызов EndInvoke несколько раз - это нормально - я не знаю навскидку. - person Jon Skeet; 10.02.2009

Thread.Abort, конечно, закроет поток, так как вызовет Win32 TerminateThread.

Результат этого действия будет зависеть от того, как ваш API хочет, чтобы его закрывал TerminateThread.

Если ваш метод называется что-то вроде NuclearPlant.MoveRod() или Defibrillator.Shock(), я лучше подожду эти 30 секунд.

Этот метод не дает жертве возможности выполнить некоторую очистку:

TerminateThread используется для выхода из потока. Когда это происходит, целевой поток не имеет возможности выполнить какой-либо код пользовательского режима. Библиотеки DLL, присоединенные к потоку, не уведомляются о завершении потока. Система освобождает начальный стек потока.

Как указано в MSDN:

TerminateThread — опасная функция, которую следует использовать только в самых крайних случаях. Вы должны вызывать TerminateThread только в том случае, если вы точно знаете, что делает целевой поток, и вы контролируете весь код, который может выполняться целевым потоком во время завершения. Например, TerminateThread может привести к следующим проблемам:

  • Если целевой поток владеет критической секцией, критическая секция не будет освобождена.
  • Если целевой поток выделяет память из кучи, блокировка кучи не будет снята.
  • Если целевой поток выполняет определенные вызовы ядра 32, когда он завершается, состояние ядра 32 для процесса потока может быть несогласованным.
  • Если целевой поток манипулирует глобальным состоянием общей библиотеки DLL, состояние библиотеки DLL может быть уничтожено, что повлияет на других пользователей библиотеки DLL.
person Quassnoi    schedule 10.02.2009
comment
Похоже, вы не считаете, что прерывание — безопасная идея, и я понимаю, почему по вашим комментариям. Итак, если Abort — это то, чего следует избегать, есть ли у вас альтернативное решение? - person Chad; 10.02.2009
comment
Если у вашего API нет возможности остановить метод, альтернативного решения нет. Все такие решения, если таковые имеются, полагаются на способность потока реагировать на внешние сигналы и действовать соответствующим образом. Если поток этого не делает, TerminateThread — единственный способ остановить его. - person Quassnoi; 10.02.2009