Установите тайм-аут на операцию
У меня есть объект obj
, который является сторонним компонентом,
// this could take more than 30 seconds
int result = obj.PerformInitTransaction();
Я не знаю, что происходит внутри.
Я знаю, что если это займет больше времени, это не удастся.
как настроить механизм тайм-аута для этой операции, так что если он занимает более 30 секунд, я просто бросаю MoreThan30SecondsException
?
Ответы
Ответ 1
Вы можете запустить операцию в отдельном потоке, а затем поместить таймаут в операцию объединения потоков:
using System.Threading;
class Program {
static void DoSomething() {
try {
// your call here...
obj.PerformInitTransaction();
} catch (ThreadAbortException) {
// cleanup code, if needed...
}
}
public static void Main(params string[] args) {
Thread t = new Thread(DoSomething);
t.Start();
if (!t.Join(TimeSpan.FromSeconds(30))) {
t.Abort();
throw new Exception("More than 30 secs.");
}
}
}
Ответ 2
Более просто используя Task.Wait(TimeSpan)
:
using System.Threading.Tasks;
var task = Task.Run(() => obj.PerformInitTransaction());
if (task.Wait(TimeSpan.FromSeconds(30)))
return task.Result;
else
throw new Exception("Timed out");
Ответ 3
Если вы не хотите блокировать основной поток, вы можете использовать System.Threading.Timer:
private Thread _thread;
void Main(string[] args)
{
_thread = new ThreadStart(ThreadEntry);
_thread.Start();
Timer timer = new Timer(Timeout,null,30000,Timeout.Infinite);
}
void ThreadEntry()
{
int result = obj.PerformInitTransaction();
}
void TimeOut(object state)
{
// Abort the thread - see the comments
_thread.Abort();
throw new ItTimedOutException();
}
Джон Скит имеет менее сильный способ ( "Отключение рабочих тем" Изящно) остановки потока, чем отмена.
Однако, поскольку вы не контролируете операции PerformInitTransaction()
, вы не можете сделать это, когда Abort завершится с ошибкой и оставляет объект в недопустимом состоянии. Как уже упоминалось, если вы можете очистить все, что отменило PerformInitTransaction
, то вы можете сделать это, поймав ThreadAbortException
, хотя, поскольку он является сторонним вызовом, это будет означать догадывание состояния, в котором вы оставили свой метод в.
PerformInitTransaction
должен действительно быть тем, который обеспечивает тайм-аут.
Ответ 4
Вам нужно быть осторожным, чтобы прервать такую операцию, особенно в том случае, если в стороннем компоненте вы (возможно) не имеете доступа к изменяемому коду.
Если вы прервите операцию, вы не узнаете, в каком состоянии вы оставили базовый класс. Например, он, возможно, приобрел блокировку, и ваш вопрос заставил эту блокировку не выпускаться. Даже если вы уничтожили объект после отмены операции, он, возможно, изменил какое-то состояние, глобальное для него, и поэтому вы не сможете надежно создать новый экземпляр без перезагрузки.
Ответ 5
Вы можете посмотреть вызов метода в потоке и таймауте, прервать поток и повысить исключение. Кроме того, в этом случае вам придется обрабатывать исключение ThreadBorted.
Ответ 6
Хороший пример универсального решения для этого, используя вспомогательный класс здесь.
Он использует делегат Action, чтобы избежать создания/уничтожения потока, показанного в предыдущем примере.
Надеюсь, это поможет.