Прервать нить без петель мгновенно без прерывания или приостановки - PullRequest
2 голосов
/ 03 апреля 2012

Я реализую библиотеку протоколов. Здесь упрощенное описание.

Главный поток в основной функции всегда проверяет, доступны ли некоторые данные в сетевом потоке (в пределах 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();         
     }
}

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

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

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

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

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

Ответы [ 4 ]

4 голосов
/ 03 апреля 2012

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

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

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

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

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

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

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

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

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

1 голос
/ 03 апреля 2012

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

1 голос
/ 03 апреля 2012

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

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

1 голос
/ 03 апреля 2012

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...