Поделиться через


Приостановка и прерывание потоков

Наиболее распространенными способами синхронизации действий потоков являются блокировка и освобождение потоков, блокировка объектов или регионов кода. Дополнительные сведения об этих механизмах запирания и блокировки см. в обзоре примитивов синхронизации.

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

Метод Thread.Sleep

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

Один поток не может вызывать Thread.Sleep в другом потоке. Thread.Sleep — это статический метод, который всегда заставляет текущий поток засыпать.

Вызов Thread.Sleep со значением Timeout.Infinite приводит к спящему потоку, пока он не будет прерван другим потоком, который вызывает метод Thread.Interrupt в спящем потоке или пока не завершится вызовом метода Thread.Abort. В следующем примере показаны оба метода прерывания спящего потока.

using System;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // Interrupt a sleeping thread.
      var sleepingThread = new Thread(Example.SleepIndefinitely);
      sleepingThread.Name = "Sleeping";
      sleepingThread.Start();
      Thread.Sleep(2000);
      sleepingThread.Interrupt();

      Thread.Sleep(1000);

      sleepingThread = new Thread(Example.SleepIndefinitely);
      sleepingThread.Name = "Sleeping2";
      sleepingThread.Start();
      Thread.Sleep(2000);
      sleepingThread.Abort();
   }

   private static void SleepIndefinitely()
   {
      Console.WriteLine($"Thread '{Thread.CurrentThread.Name}' about to sleep indefinitely.");
      try {
         Thread.Sleep(Timeout.Infinite);
      }
      catch (ThreadInterruptedException) {
         Console.WriteLine($"Thread '{Thread.CurrentThread.Name}' awoken.");
      }
      catch (ThreadAbortException) {
         Console.WriteLine($"Thread '{Thread.CurrentThread.Name}' aborted.");
      }
      finally
      {
         Console.WriteLine($"Thread '{Thread.CurrentThread.Name}' executing finally block.");
      }
      Console.WriteLine($"Thread '{Thread.CurrentThread.Name} finishing normal execution.");
      Console.WriteLine();
   }
}
// The example displays the following output:
//       Thread 'Sleeping' about to sleep indefinitely.
//       Thread 'Sleeping' awoken.
//       Thread 'Sleeping' executing finally block.
//       Thread 'Sleeping finishing normal execution.
//
//       Thread 'Sleeping2' about to sleep indefinitely.
//       Thread 'Sleeping2' aborted.
//       Thread 'Sleeping2' executing finally block.
Imports System.Threading

Module Example
    Public Sub Main()
        ' Interrupt a sleeping thread. 
        Dim sleepingThread = New Thread(AddressOf Example.SleepIndefinitely)
        sleepingThread.Name = "Sleeping"
        sleepingThread.Start()
        Thread.Sleep(2000)
        sleepingThread.Interrupt()

        Thread.Sleep(1000)

        sleepingThread = New Thread(AddressOf Example.SleepIndefinitely)
        sleepingThread.Name = "Sleeping2"
        sleepingThread.Start()
        Thread.Sleep(2000)
        sleepingThread.Abort()
    End Sub

    Private Sub SleepIndefinitely()
        Console.WriteLine("Thread '{0}' about to sleep indefinitely.",
                          Thread.CurrentThread.Name)
        Try
            Thread.Sleep(Timeout.Infinite)
        Catch ex As ThreadInterruptedException
            Console.WriteLine("Thread '{0}' awoken.",
                              Thread.CurrentThread.Name)
        Catch ex As ThreadAbortException
            Console.WriteLine("Thread '{0}' aborted.",
                              Thread.CurrentThread.Name)
        Finally
            Console.WriteLine("Thread '{0}' executing finally block.",
                              Thread.CurrentThread.Name)
        End Try
        Console.WriteLine("Thread '{0}' finishing normal execution.",
                          Thread.CurrentThread.Name)
        Console.WriteLine()
    End Sub
End Module
' The example displays the following output:
'       Thread 'Sleeping' about to sleep indefinitely.
'       Thread 'Sleeping' awoken.
'       Thread 'Sleeping' executing finally block.
'       Thread 'Sleeping finishing normal execution.
'       
'       Thread 'Sleeping2' about to sleep indefinitely.
'       Thread 'Sleeping2' aborted.
'       Thread 'Sleeping2' executing finally block.

Прерывание потоков

Вы можете прервать ожидающий поток, вызвав метод Thread.Interrupt в блокированном потоке для генерации ThreadInterruptedException, который выводит этот поток из блокирующего вызова. Поток должен перехватывать ThreadInterruptedException и делать все, что необходимо для продолжения работы. Если поток игнорирует исключение, среда выполнения перехватывает исключение и останавливает поток.

Примечание.

Если целевой поток не блокируется при вызове Thread.Interrupt, поток не прерывается до тех пор, пока он не блокируется. Если поток никогда не блокируется, он может завершиться без прерывания.

Если ожидание является управляемым ожиданием, то Thread.Interrupt и Thread.Abort сразу же пробуждают поток. Если ожидание является неуправляемым ожиданием (например, вызов платформы к функции Win32 WaitForSingleObject), ни Thread.Interrupt, ни Thread.Abort не может контролировать поток, пока он не возвращается в управляемый код или не вызывает его. В управляемом коде поведение выглядит следующим образом:

См. также