2015-11-22 14 views
7

.NET 4.5.1: Sembra che non sia possibile annullare un metodo di blocco eseguito all'interno di un'attività che utilizza il timeout predefinito CancellationTokenSource.C#: CancellationToken non annulla il metodo di blocco

class Program 
{ 
    static void Main(string[] args) 
    { 
     var cts = new System.Threading.CancellationTokenSource(); 

     System.Console.CancelKeyPress += (s, e) => 
     { 
      e.Cancel = true; 
      cts.Cancel(); 
     }; 

     MainAsync(args, cts.Token).Wait(); 
    } 

    // MainAsync from http://stackoverflow.com/questions/9208921/async-on-main-method-of-console-app 
    static async Task MainAsync(string[] args, System.Threading.CancellationToken token) 
    { 
     Console.WriteLine("Starting MainAsync"); 
     var cts = new System.Threading.CancellationTokenSource(3000); 
     var task = Task.Factory.StartNew(() => 
     { 
      Console.WriteLine("Starting task..."); 
      var t = new System.Net.Sockets.TcpClient(); 
      var buffer = new byte[t.ReceiveBufferSize]; 
      t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337)); 

      Console.WriteLine("Recieving..."); 
      t.Client.Receive(buffer); 
      Console.WriteLine("Finished Recieving..."); 

      return true; 
     }, cts.Token); 

     var success = await task; 

     Console.WriteLine("Did the task complete succesfuly?", success); 
    } 
} 

L'uscita dal sopra Corto, Self Contained, esempio corretto (spero che sia corretto) è:

Starting MainAsync 
Starting task... 
Recieving... 

Perché il compito non cancella, non viene generata un'eccezione?

+0

Utilizzare socket.receive come in questo caso è una chiamata di blocco: è necessario fornire un timeout o un utilizzo asincrono in modo da poter rivalutare il token di annullamento durante l'elaborazione. CancellationToken non terminerà magicamente le chiamate di blocco per te. – Joe

risposta

3

Non sono sicuro, ma suppongo che tu stia confondendo "la richiesta di cancellazione" con "terminazione o interruzione di un thread/attività". Queste sono due cose completamente diverse. In base alla descrizione dello Canellation in Managerd Threads, la funzionalità fornita consente di inviare qualcosa come un segnale, indicando che l'operazione in corso deve essere interrotta.

Come e se reagire su quel segnale è - come programmatore - fino a voi.

Nel tuo esempio hai iniziato una nuova attività

var task = Task.Factory.StartNew(() => 
{  
    Console.WriteLine("Starting task..."); 
    var t = new System.Net.Sockets.TcpClient(); 
    var buffer = new byte[t.ReceiveBufferSize]; 
    t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337)); 

    Console.WriteLine("Recieving..."); 
    t.Client.Receive(buffer); 
    Console.WriteLine("Finished Recieving..."); 

    return true; 
}, cts.Token); 

che non gestisce la cancellazione né è adatto a farlo. La canellazione verrebbe utilizzata per es. se vuoi uscire da un ciclo con molte iterazioni, quindi verificherai in ogni iterazione se lo CancellationToken.IsCancellationRequested è stato impostato su true o no. Se è così, puoi reagire di conseguenza.

Quello che vuoi è interrompere il thread che è dietro l'attività corrente che è a mio parere possibile solo creando una nuova istanza della classe Thread per te stesso e gestisci l'interruzione di conseguenza.

Problemi correlati