Уничтожение потока .NET - PullRequest
19 голосов
/ 27 июня 2009

Я создал поток, выполняющий определенный метод. Но иногда я хотел бы убить поток, даже если он все еще работает. Как я могу это сделать? Я попытался Thread.Abort (), но он отображает окно с сообщением "Тема прервана". Что я должен делать?

Ответы [ 7 ]

48 голосов
/ 27 июня 2009

Не звоните Thread.Abort()!

Thread.Abort опасно. Вместо этого вы должны сотрудничать с потоком, чтобы его можно было спокойно отключить. Поток должен быть спроектирован так, чтобы ему было приказано уничтожить себя, например, с помощью логического флага keepGoing, который вы установили в false, когда хотите остановить поток. Тогда поток будет иметь что-то вроде

while (keepGoing)
{
    /* Do work. */
}

Если поток может заблокировать Sleep или Wait, вы можете разорвать его из этих функций, вызвав Thread.Interrupt(). Затем нить должна быть подготовлена ​​для обработки ThreadInterruptedException:

try
{
    while (keepGoing)
    {
        /* Do work. */
    }
}
catch (ThreadInterruptedException exception)
{
    /* Clean up. */
}
26 голосов
/ 27 июня 2009

Вы должны действительно вызывать Abort () только в крайнем случае. Вместо этого вы можете использовать переменную для синхронизации этого потока:

volatile bool shutdown = false;

void RunThread()
{
   while (!shutdown)
   {
      ...
   }
}

void StopThread()
{
   shutdown = true;
}

Это позволяет вашему потоку полностью завершить то, что он делал, оставляя ваше приложение в известном исправном состоянии.

9 голосов
/ 27 июня 2009

Самый правильный и потокобезопасный способ - использовать WaitHandle для подачи сигнала потоку, когда он должен остановиться. В основном я использую ManualResetEvent.

В вашей теме вы можете иметь:

private void RunThread()
{
    while(!this.flag.WaitOne(TimeSpan.FromMilliseconds(100)))
    {
        // ...
    }
}

, где this.flag - это экземпляр ManualResetEvent. Это означает, что вы можете вызвать this.flag.Set() извне потока, чтобы остановить цикл.

Метод WaitOne вернет true, только если флаг установлен. В противном случае он истечет по истечении заданного времени ожидания (в этом примере 100 мс), и поток снова будет проходить через цикл.

7 голосов
/ 20 сентября 2010

Не стоит убивать поток. Лучше сигнализировать о том, что он должен остановиться и изящно закончиться. Существуют различные способы сделать это.

  • Используйте Thread.Interrupt, чтобы ткнуть его, если он заблокирован.
  • Опрос переменной флага.
  • Используйте класс WaitHandle для отправки сигнала.

Мне не нужно перефразировать, как можно использовать каждый метод, поскольку я уже сделал это в этом ответе .

2 голосов
/ 19 мая 2012

Я согласен с Джоном Б

volatile bool shutdown = false;

void RunThread()
{

try
{
    while (!shutdown)
    {
        /* Do work. */
    }
}
catch (ThreadAbortException exception)
{
    /* Clean up. */
}
}

void StopThread()
{
   shutdown = true;
}
2 голосов
/ 27 июня 2009

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

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

1 голос
/ 19 мая 2012

В моем классе WebServer также есть примеры уничтожения тем ...

https://net7ntcip.codeplex.com/SourceControl/changeset/view/89621#1752948

Я бы сказал, что с Abort все в порядке, просто поймите, к каким последствиям это относится ... если вы указываете состояние, прежде чем продолжительная задача Abort сработает, но требуются флаги, такие как (ShouldStop или ActionBranch и т. Д.)

Посмотрите на примеры!

...