Sospensione e interruzione di thread

Le tecniche più comuni per sincronizzare le attività dei thread consistono nel blocco e nel rilascio dei thread oppure nel blocco di oggetti o aree di codice. Per altre informazioni su questi meccanismi di blocco, vedere Panoramica delle primitive di sincronizzazione.

È anche possibile fare in modo che i thread vengano sospesi automaticamente. Quando i thread sono bloccati o sospesi, è possibile usare un'eccezione ThreadInterruptedException per interromperne lo stato di attesa.

Metodo Thread.Sleep

Se si chiama il metodo Thread.Sleep, il thread corrente viene bloccato immediatamente per il numero di millisecondi o l'intervallo di tempo passato al metodo, cedendo il resto della porzione di tempo a un altro thread. Una volta trascorso tale intervallo, il thread inattivo riprende l'esecuzione.

Un thread non può chiamare Thread.Sleep su un altro thread. Thread.Sleep è un metodo statico che determina sempre il thread corrente da sospendere.

Se si chiama Thread.Sleep con un valore di Timeout.Infinite, un thread rimarrà sospeso finché non verrà interrotto da un altro thread tramite una chiamata al metodo Thread.Interrupt nel thread sospeso o finché non verrà terminato da una chiamata al relativo metodo Thread.Abort. L'esempio seguente illustra entrambi i metodi per interrompere un thread inattivo.

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.

Interruzione di thread

È possibile interrompere un thread in attesa chiamando il metodo Thread.Interrupt sul thread bloccato per generare un'eccezione ThreadInterruptedException, che fa uscire il thread dalla chiamata che lo blocca. Il thread dovrebbe intercettare l'eccezione ThreadInterruptedException ed eseguire le operazioni appropriate per continuare a funzionare. Se il thread ignora l'eccezione, l'ambiente di esecuzione la intercetta e interrompe il thread.

Nota

Se il thread di destinazione non è bloccato al momento della chiamata del metodo Thread.Interrupt, il thread non subisce interruzioni finché non viene bloccato. Se il thread non si blocca, verrà completato senza subire alcuna interruzione.

Se un'attesa è di tipo gestito, sia Thread.Interrupt che Thread.Abort riporteranno immediatamente il thread allo stato di attività. Nel caso di un'attesa non gestita, ad esempio un platform invoke alla funzione Win32 WaitForSingleObject, né Thread.InterruptThread.Abort potrà assumere il controllo del thread fino alla restituzione o alla chiamata nel codice gestito. Di seguito è descritto il comportamento nel codice gestito.

Vedi anche