Vb.net прервать асинхронный метод вызова после тайм-аута

StackOverflow https://stackoverflow.com/questions/3876245

Вопрос

Vb.net 2010, .net 4

Всем привет,

У меня есть объект System.timers.timer, который выполняет некоторые работы на своем истечении события:

Private Sub MasterTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles MasterTimer.Elapsed
    MasterTimer.Enabled = False
    '...work...
    MasterTimer.Enabled = True
End Sub

Моя проблема в том, что работа, которую она делает иногда застряла. Часть работы является последовательная связь, поэтому может быть застрял в ожидании ответа от чего-либо. Я уже немного изменил свой последовательный код связи, чтобы надеяться, что решить проблему. Тем не менее, этот таймер в основном является сердцебиением приложения для управления производством, и он очень плохо, если бы он останавливался по какой-либо причине. Я думал, что может быть приятно поставить в бесперебойную тайм-аут, так что, если «работа» забирает слишком долго, таймер может повторно позволить себе и попробовать еще раз. Я думал о чем-то вроде этого:

Переместите работу в подпрограмму и создайте делегат:

Private Delegate Sub WorkDelegate()
Private Sub Work()
   '...work...
End Sub

Позвоните на работу, вызывая делегата, а затем используйте WaiteNe (Timeout) на IASYNCRESULT, чтобы указать тайм-аут:

Private Sub MasterTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles MasterTimer.Elapsed
    MasterTimer.Enabled = False
    Dim workDel as New WorkDelegate(AddressOf Work)
    Dim result as IAsyncResult = workDel.BeginInvoke
    result.AsyncWaitHandle.WaitOne(CInt(MasterTimer.Interval))
    MasterTimer.Enabled = True
End Sub

Но мой вопрос: будет ли это вызвать проблему, если работа () действительно застрял где-то? В этом он повторно попал в подпрограмму, который уже работает? Есть ли способ прервать работу (), если он не закончил после тайм-аута? Другими словами, просто прекратите выполнение работы (), если результат.

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

Заранее большое спасибо!

Я хотел бы добавить что-то:

Несмотря на то, что я намерен сделать некоторые переписаны в соответствии с предложениями Hans, я уже запланировал день тестирования, чтобы попытаться изолировать источник этой ошибки. До сих пор это произошло только при запуске скомпилированного приложения. Я провел сегодня (и вчерашний день), пытаясь воспроизвести замораживание во время работы в режиме отладки, чтобы, возможно, я мог бы добавить некоторые точки останова и выяснить, что происходит. До сих пор программа не заморожена в режиме отладки. Мне просто интересно, есть ли что-то отличное от этой среды отладки, которая может объяснить это. Это может быть, просто потому, что я «счастливчик», но у меня, вероятно, в три раза средняя длина времени, после которой программа замерзнет при запуске исполняемого ... Опять же, я довольно невежественнее, но есть что-нибудь Уникальный о отладочной среде, которая могла бы объяснить это? Я обновись снова, если он замерзнет.

Это было полезно?

Решение

Это выходит не так на самой первой строке кода. System.timers.timer Class довольно ICKY, нет абсолютно никакой гарантии, что остановка вызова () предотвратит другой звонок. Таймер использует Threadpool.QueueUserWorkeTem, чтобы сделать прошедший вызов обработчика событий. Если Threadpool занят, это может в конечном итоге в очередь несколько вызовов, ожидание, чтобы получить GO-адрес от планировщика TP для запуска. Остановка таймера не мешает бежать те нити ожидающих. Без использования блокировки эти потоки будут сильно наступить друг на друга и запустить состояние вашего сообщения.

Безопасный - это System.Threading.timer с нулевом периодом, поэтому вы получите только один обратный вызов. Перезарядите таймер с помощью метода изменения ().

Призыв метод NewingInvoke () делегата (), а затем блокировка его завершения не имеет смысла. Просто звонок вызывает (). Сохраняет вас от сжигания другой нити.

Да, если метод «работа» никогда не возвращается, то у вас есть проблема. Неразрешимый.

Многие из этих страданий могут исчезнуть, если вы избегаете использовать опрос, чтобы увидеть, есть ли что-то доступное на последовательном порте. Пусть это скажет вам, что есть что-то стоящее. Это поднимает событие DataAreceied, на потоке ThreadPool, всякий раз, когда в буфере приема есть хотя бы один байт. Используя свой свойство WRITETIMEOUT, также является отличным способом избежать застряния, когда что-то асисна с протоколом связи или устройством. Снижая одну нить и делая блокировку чтения звонков тоже хорошо работает.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top