Уничтожение потока.NET

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

8 ответов

Не звони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. */
}

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

volatile bool shutdown = false;

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

void StopThread()
{
   shutdown = true;
}

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

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

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

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

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

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

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

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

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

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

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

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

volatile bool shutdown = false;

void RunThread()
{

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

void StopThread()
{
   shutdown = true;
}

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

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

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

Проверьте это на примерах!

Редактировать:

  1. Я создал небольшой класс для этого

  2. Заметил, что это не работает с async/await

  3. Опубликовал обновление в классе, затем Теодор Зулиас (спасибо :)) сообщил мне, что эта идея ошибочна.

  4. Теперь я публикую исходный класс (не работает с async/await!)

            var t = new StopAbleThread(isShutDown =>
     {
       Console.WriteLine("a");
       while (!isShutDown())
       {
         Console.WriteLine("b");
         Thread.Sleep(TimeSpan.FromMinutes(10));
       }
     }  )   
    
    { IsBackground = true };
       t.Start( );
    

Остановить ветку так:

      t.Stop();

Класс:

      public class StopAbleThread
{
  public bool IsBackground
  {
    set => _thread.IsBackground = value;
  }

  private readonly Thread _thread;
  private volatile bool _shutdown;

  public delegate bool IsShutDown( );
  public delegate void CodeToRun( IsShutDown isShutDown );


  public StopAbleThread( CodeToRun codeToRun )
  {
    _thread = new Thread( ( ) =>
    {
      try
      {
        codeToRun( _IsShutDown );
      }
      catch( ThreadInterruptedException )
      {
        //ignore
      }
    } );
  }

  private bool _IsShutDown( )
  {
    return _shutdown;
  }

  public void Start( )
  {
    _thread.Start( );
  }

  public void Stop( )
  {
    _shutdown = true;
    _thread.Interrupt( );
  }
}
Другие вопросы по тегам