Завершить поток после интервала, если он не возвращен

У меня есть поток, который захватывает некоторые данные из сетевого или последовательного порта. Поток должен завершаться (или возвращать false), если данные не получены в течение 5 секунд.

Другими словами, если запуск потока занимает более 5 секунд, он должен остановиться.

Я пишу на С#, но любой язык .NET в порядке.

Ответы

Ответ 1

Существует два подхода:

1. Инкапсулированный тайм-аут

Поток, считывающий данные из сетевого или последовательного порта, может измерять время, прошедшее с момента его запуска, и ждать данных не более, чем оставшееся время. API-интерфейсы сети обычно предоставляют средства для указания тайм-аута для операции. Следовательно, выполняя простую арифметику DateTime, вы можете инкапсулировать управление тайм-аутом в свой рабочий поток.

2. Внешний тайм-аут

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

// start the worker thread
...

// give it no more than 5 seconds to execute
if (!workerThread.Join(new TimeSpan(0, 0, 5)))
{    
    workerThread.Abort();
}

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

Ответ 2

Любой механизм должен позволять вам указывать таймаут при чтении. Например, перед выполнением чтения вы можете установить NetworkStream.ReadTimeout на 5000. Вы должны иметь возможность сделать что-то подобное для последовательных портов.

Чтение, которое имеет тайм-аут, вернет 0 из Stream.Read() - так вы можете узнать, действительно ли произошел тайм-аут.

Обратите внимание, что использование Thread.Abort() устарело, как .NET 2.0, для некоторых серьезных проблем, которые оно может вызвать. Теоретически вы можете использовать Thread.Interrupt(), но это ничего не сделает, когда поток заблокирован в неуправляемом коде (включая ввод-вывод). Использование таймаутов чтения является правильным способом решения этой проблемы.

Ответ 3

Если вы используете управляемый код для блокировки потока, вы можете использовать Thread.Abort, чтобы прервать выполнение. Если вы используете сторонний код или COM-взаимодействие, нет способа прекратить выполнение потока. Единственный способ - установить для параметра Thread.isBackroundThread значение true, а затем завершить процесс...

Ответ 4

Вы упомянули, что читаете из "сети". Если вы используете NetworkStream для чтения, вы можете указать ReadTimeout как 5000 (это в миллисекундах). Это будет ждать 5 секунд, после чего вернется после этого, если данные не будут прочитаны. Однако, если он находится в процессе или чтении, я думаю, что он тоже может вернуться, поэтому будьте осторожны. Я никогда ничего не делал с последовательным API, поэтому я не уверен, есть ли там такая настройка.

Ответ 5

Это двухпоточное решение.

Пример:

Thread tParent = new Thread(new ThreadStart(() =>
{
    Thread t = new Thread(AsyncMethod);
    t.Start();
    Thread.Sleep(5000);
    if (t.IsAlive) t.Abort();
}));

Помните:

Плохая практика - использовать такой метод. Вызов Thread.Abort() не рекомендуется. Используйте Thread Synchronization, используя WaitHandles. Например, AutoResetEvent.

Ответ 6

Я думаю, что поток наблюдателей - это то, что вам нужно. Начать другой поток одновременно и передать поток последовательного порта в качестве параметра этого потока. Запустите наблюдателя с пятисекундным сном и проверьте состояние потока.

Теперь о завершении потока см. ответ alex, его право!