2010-05-31 11 views
5

J'essaie d'implémenter un thread de travail annulable en utilisant les nouvelles constructions de thread dans l'espace de noms System.Threading.Tasks. Jusqu'à présent, j'ai ont mis au point cette mise en œuvre:Comment implémenter le thread de travail annulable

public sealed class Scheduler 
{ 
    private CancellationTokenSource _cancellationTokenSource; 
    public System.Threading.Tasks.Task Worker { get; private set; } 

    public void Start() 
    { 
     _cancellationTokenSource = new CancellationTokenSource(); 

     Worker = System.Threading.Tasks.Task.Factory.StartNew(
      () => RunTasks(_cancellationTokenSource.Token), 
      _cancellationTokenSource.Token 
     ); 
    } 

    private static void RunTasks(CancellationToken cancellationToken) 
    { 
     while (!cancellationToken.IsCancellationRequested) 
     { 
      Thread.Sleep(1000); // simulate work 
     } 
    } 

    public void Stop() 
    { 
     try 
     { 
      _cancellationTokenSource.Cancel(); 
      Worker.Wait(_cancellationTokenSource.Token); 
     } 
     catch (OperationCanceledException) 
     { 
      // OperationCanceledException is expected when a Task is cancelled. 
     } 
    } 
} 

Lorsque je Stop() retours Worker.Status attendent d'être TaskStatus.Canceled.
Mes tests unitaires ont montré que dans certaines conditions Worker.Status reste à TaskStatus.Running.

Est-ce une manière correcte d'implémenter un thread de travail annulable?

Répondre

5

Je crois que le problème est dans votre appel à

Worker.Wait(_cancellationTokenSource.Token); 

qui attend le jeton à signaler - ce qui est déjà, parce que vous venez appelé Cancel(). Si vous changez que juste

Worker.Wait(); 

alors je crois que vous verrez un état de RanToCompletion. Vous ne verrez pas Annulé, car votre tâche ne lance pas OperationCanceledException. Si vous changez de méthode RunTasks pour appeler

cancellationToken.ThrowIfCancellationRequested() 

à la fin, alors vous aurez besoin de prendre un AggregateException dans Stop - mais alors vous verrez un état de Canceled à la fin. Au moins, c'est ce que mon expérience montre :)

+0

Oui, cela a résolu le problème Merci. –