Pausando e interrompendo threads

As formas mais comuns para sincronizar as atividades de threads são segmentos de bloco e versão ou objetos de bloqueio ou regiões de código. Para saber mais sobre esse bloqueio e os mecanismos de bloqueio, confira Visão geral de primitivos de sincronização.

Você também pode fazer com que threads se coloquem no modo de suspensão. Quando os threads estão bloqueados ou suspensos, você pode usar um ThreadInterruptedException para removê-los dos estados de espera.

O método Thread.Sleep

Chamar o método Thread.Sleep faz com que o thread atual seja bloqueado imediatamente pelo número de milissegundos ou o intervalo de tempo que você passa para o método e produza o resto do intervalo de tempo para outro thread. Depois que o intervalo expira, o thread em suspensão retoma a execução.

Um thread não pode chamar Thread.Sleep em outro thread. Thread.Sleep é um método estático que sempre faz com que o thread atual entre no modo de suspensão.

Chamar Thread.Sleep com um valor Timeout.Infinite faz com que um thread seja suspenso até que ele seja interrompido por outro thread que chame o método Thread.Interrupt no thread em suspensão ou até que ele seja encerrado por uma chamada ao método Thread.Abort. O exemplo a seguir ilustra os dois métodos para interromper um thread suspenso.

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 '{0}' about to sleep indefinitely.",
                        Thread.CurrentThread.Name);
      try {
         Thread.Sleep(Timeout.Infinite);
      }
      catch (ThreadInterruptedException) {
         Console.WriteLine("Thread '{0}' awoken.",
                           Thread.CurrentThread.Name);
      }
      catch (ThreadAbortException) {
         Console.WriteLine("Thread '{0}' aborted.",
                           Thread.CurrentThread.Name);
      }
      finally
      {
         Console.WriteLine("Thread '{0}' executing finally block.",
                           Thread.CurrentThread.Name);
      }
      Console.WriteLine("Thread '{0} finishing normal execution.",
                        Thread.CurrentThread.Name);
      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.

Interrompendo threads

Você pode interromper um thread em espera chamando o método Thread.Interrupt no thread bloqueado para lançar um ThreadInterruptedException, o que remove o thread da chamada de bloqueio. O thread deve capturar o ThreadInterruptedException e fazer o que for apropriado para continuar funcionando. Se o thread ignorar a exceção, o runtime capturará a exceção e interromperá o thread.

Observação

Se o thread de destino não for bloqueado quando Thread.Interrupt for chamado, o thread não será interrompido até ser bloqueado. Se o thread nunca for bloqueado, ele poderá ser concluído sem nunca ser interrompido.

Se uma espera for uma espera gerenciada, Thread.Interrupt e Thread.Abort ativarão o thread imediatamente. Se uma espera for uma espera não gerenciada (por exemplo, uma chamada de invocação de plataforma para a função Win32 WaitForSingleObject), Thread.Interrupt e Thread.Abort não poderão assumir o controle do thread até que ele chame o código gerenciado ou retorne a ele. No código gerenciado, o comportamento é o seguinte:

Confira também