2012-04-03 8 views
2

Я реализую библиотеку протоколов. Вот упрощенное описание.Прекратить беззаметную нить мгновенно без прерывания или приостановки

Основной поток в основной функции всегда будет проверять, доступны ли некоторые данные в сетевом потоке (внутри tcpclient). Скажем, ответ - это принятое сообщение, а поток - работающий поток.

thread = new Thread(new ThreadStart(function)); 
thread.IsBackground = true; 
thread.Start(); 

while(true){ 

response = receiveMessage(); 

if (response != null) 
    {     
     thread.Suspend(); 
     //I am searching for an alternative for the line above and not thread.Abort(). 

     thread2 = new Thread(new ThreadStart(function2)); 
     thread2.IsBackground = true; 
     thread2.Start();   
    } 
} 

До сих пор так хорошо, есть на самом деле больше сообщений, чтобы прийти в то время цикла и есть также StateMachine для обработки разного рода входящих сообщений, но это должно быть достаточно. (Есть также не только функции «функция» и «функция2»).

Так или иначе, как функции выглядят внутри, в этом приложении неясно, поскольку протокол скрыт от программиста и предназначен для библиотеки. Это означает, что протокол запустит некоторые определенные программистом функции в виде потока в зависимости от того, в каком состоянии в протоколе есть программа.

Итак, если получен специальный отклик (например, сообщение CallAnotherFunction), я хочу закончить поток (здесь называется «поток»), скажем, в течение 100 мс. Но я не знаю, выполняется ли он в цикле или без, и сколько требуется обработки, пока оно не завершится.

Как остановить эти потоки без устаревших функций приостановки или исключения из-за прерывания? (Обратите внимание, что я не могу заставить программиста выполнять функции ThreadAbortException.)

Или мне нужна другая программная архитектура? (Btw Я решил поместить цикл в receiveMessage для опроса сетевого потока в главную функцию, так как в любое время может появиться сообщение).

+0

Мы что-то упускаем? Изменить while (true), while (keepLooping), а затем внутри цикла, если вы обнаружите, что вы не устанавливаете его в false, поток заканчивается изящно ???? –

ответ

4

Запуск нитки без надежного способа ее прекращения - это плохая практика. Suspend/Abort - один из тех ненадежных способов прекратить поток, потому что вы можете прекратить поток в состоянии, которое развращает всю вашу программу, и вы не можете избежать этого.

Вы можете увидеть, как убить нить безопасно здесь: Killing a .NET thread

Если «пользователь» дает вам метод для запуска в потоке, то пользователь должен также дать вам метод, чтобы остановить код от Бег. Подумайте об этом как о контракте: вы обещаете пользователю, что вы вызовете метод stop, и обещают, что метод stop фактически остановит поток. Если ваш пользователь нарушает этот контракт, тогда они будут нести ответственность за возникающие проблемы, что хорошо, потому что вы не хотите нести ответственность за ошибки своего пользователя :).

Обратите внимание, что я не могу заставить программиста функций улавливать исключение ThreadAbortException.

Поскольку Приостановка/Прервать это плохая практика, программист не должен поймать ThreadAbortException, однако они должны поймать ThreadInterruptedException как часть их «контракт.»

Помните, что есть две ситуации, вам нужно беспокоиться о:

  1. поток выполняется код.
  2. Поток находится в заблокированном состоянии.

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

В случае, когда поток находится в состоянии блокировки и не блокирует конструкцию уведомления (т.е. семафор, событие ручного сброса и т. Д.), Тогда вы должны позвонить Thread.Interrupt(), чтобы получить его из состояния блокировки - пользователь должен обрабатывать ThreadInterruptedException.

1

Suspend действительно злой, особенно в том виде, как вы его пытаетесь использовать, - чтобы остановить выполнение потока навсегда. Он оставит все блокировки, которые были связаны с потоком, а также не будет выделять ресурсы.

Thread Abort немного лучше, так как он, по крайней мере, попытается закрыть очиститель потоков, и блокировки будут иметь шанс выйти.

Чтобы правильно это сделать, вам действительно нужен код вашей нити для сотрудничества в терминации. Событий, семафоров или даже простого значения bool, проверенного потоком, может быть достаточно.

Возможно, вам лучше перепроектировать решение, чтобы иметь очередь сообщений и обрабатывать их в отдельной теме. Специальное сообщение может просто опустошить очередь.

1

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

Я бы рассмотрел возможность использования правильных асинхронных шаблонов ввода-вывода в сочетании с Tasks, предоставленными платформой .NET, вне зависимости от правильности механизмов отмены.

+0

Я только что проверил асинхронный ввод-вывод, и кажется, что это имеет смысл, если я знаю, какое сообщение ожидается, и если он уверен, что другое сообщение не может прийти. Для моего случая мне нужно постоянно отслеживать и декодировать входящие сообщения и реагировать на них, убивая поток и запуская новую функцию в зависимости от того, какое сообщение получено. Это означает, что даже во время обратного вызова может появиться сообщение. Или я вижу здесь что-то не так? –

+0

С Async IO вы «регистрируетесь» для входящих сообщений на некоторой конечной точке. Пока сообщение не поступит, вы не будете потреблять процессорное время. В новом сообщении ваш зарегистрированный клиент будет запланирован и получит возможность обработать сообщение. В вашей роли отправителя это работает совершенно наоборот.Идея состоит в том, что в сумме требуется гораздо меньше ресурсов для подачи одинакового количества запросов - если, конечно, имеется соответствующая инфраструктура (например, интеллектуальный планировщик, асинхронные возможности ввода-вывода и т. Д.). –

1

So function относится к коду, в отношении которого у вас есть небольшой контроль? Это довольно типично для сторонних библиотек. В большинстве случаев у них нет встроенных способностей, чтобы изящно прекратить длительные операции. Поскольку вы понятия не имеете, как эти функции реализованы, у вас очень мало вариантов. Фактически, ваш единственный гарантированный безопасный вариант заключается в том, чтобы закрутить эти операции в своем собственном процессе и общаться с ними через WCF. Таким образом, если вам нужно прекратить операцию внезапно, вы просто убьете процесс. Убивание другого процесса не приведет к повреждению состояния текущего процесса, как то, что произойдет, если вы назовете Thread.Abort на поток в текущем процессе.

 Смежные вопросы

  • Нет связанных вопросов^_^