2013-10-03 2 views
3

Je développe une application WPF qui aura un "service d'indexation" en tâche de fond. Le service d'indexation utilisera un FileSystemWatcher qui surveille un dossier - lorsqu'un fichier change, le service d'indexation lira le contenu du fichier et mettra à jour un index (j'utilise Lucene.Net). Mon service d'indexation est un singleton, et sera lancé lors du démarrage de l'application comme ceci: -Tâche de fond - comment s'arrêter de manière contrôlée?

new TaskFactory().StartNew(_indexingService.StartService); 

La méthode StartService() ressemble à quelque chose comme ceci: -

private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false); 

public void StartService() 
{ 
    var watcher = new FileSystemWatcher 
    { 
     // Set the properties 
    }; 
    watcher.Changed += UpdateIndexes(); 

    _resetEvent.WaitOne(); 
} 

Lorsque l'application ferme, je compte appeler cette méthode, que je comprends mettra fin à la tâche d'arrière-plan de service d'indexation: -

public void StopService() 
{ 
    _resetEvent.Set(); 
} 

tout d'abord, est-ce le bon « modèle » pour le démarrage et arrêter une tâche d'arrière-plan qui devrait fonctionner pendant la durée de vie d'une application? Deuxièmement, à quel point cet arrêt serait-il «gracieux»? Disons que le gestionnaire d'événements Changed de watcher a déclenché et parcourt les fichiers, les lit et met à jour les index. Si la tâche a été arrêtée, ce traitement sera-t-il interrompu à mi-parcours ou la méthode du gestionnaire d'événements sera-t-elle exécutée en premier?

+1

http://msdn.microsoft.com/en-us/library/dd997364.aspx – Ani

Répondre

3

Vous pouvez utiliser un jeton d'annulation:

CancellationTokenSource CancelationToken = new CancellationTokenSource(); 
    new TaskFactory().StartNew(_indexingService.StartService,CancelationToken, 
           TaskCreationOptions.LongRunning) 
.ContinueWith(TaskCancelationCallBack,TaskContinuationOptions.OnlyOnCanceled); 

Vous annulez le jeton où dans votre application à l'aide:

CancellationTokenSource.Cancel(); 

Vous pouvez vérifier si votre jeton est annulée et jeter annuler exception la tâche de à l'intérieur:

if (CancelationToken.IsCancellationRequested) {  

    CancelationToken.Token.ThrowIfCancellationRequested(); 
}   

Vous pouvez obtenir l'état de la tâche à la fonction ContinueWith callback:

private void TaskCancelationCallBack(System.Threading.Tasks.Task task) 
{ 
    if (task.Status == System.Threading.Tasks.TaskStatus.Canceled) 
    { 
     //Canceled 
    } 
} 

EDIT: Dans ce cas, nous avons utilisé le TaskContinuationOptions.OnlyOnCanceled de sorte que le chèque dans le TaskCancelationCallBack ne serait pas nécessaire. Il sera seulement viré sur cette prémisse.

+0

La réponse est presque correcte. Il y a quelques erreurs qui doivent être fixés pour le faire fonctionner: méthode Thew ** StartNew ** attend un CancellationToken, pas CancellationTokenSource comme paramètre. Donc, vous devez passer la propriété Token à la méthode. En outre, il s'attend à ce que vous informiez quel TaskScheduler vous souhaitez utiliser. Vous pouvez passer soit Current soit Default. Il existe d'autres correctifs mineurs, mais vous y arriverez lorsque vous essaierez de compiler le code. –

0

Si vous appelez waitOne, la tâche se termine quand même.

Pour avoir une tâche de fond fait faire quelque chose, à un moment donné, il y aura besoin d'être une boucle qui traite, comme celui-ci

void ProcessItems() 
{ 
    while(workItems.Count > 0) 
    { 
     ProcessItem(workItems[0]); 
    } 
} 

Si vous voulez sauter en parachute grâce, vous pouvez faire deux choses. Dans mon exemple, j'aurais un drapeau.

bool m_IsRunning = true; 
public void Stop() 
{ 
    m_IsRunning = false; 
} 
void ProcessItems() 
{ 
    while(workItems.Count > 0 && m_IsRunning) 
    { 
      ProcessItem(workItems[0]); 
    } 
} 

Utiliser Task Parallel Library, vous pouvez également passer dans un CancellationToken.

Dans les classes de travail, l'annulation implique la coopération entre le délégué de l'utilisateur , ce qui représente une opération annulable et le code qui a demandé l'annulation. Une annulation réussie implique le code demandeur appelant le CancellationTokenSource.Annuler procédé, et le délégué utilisateur terminer l'opération en temps opportun. Vous pouvez terminer l'opération en utilisant l'une de ces options:

  • En retournant simplement du délégué. Dans de nombreux cas, cela est suffisant. Cependant, une instance de tâche qui est « annulé » de cette façon
    la transition vers l'état RanToCompletion, et non pas à l'état Annulée.

  • En jetant un OperationCanceledException et passer le jeton sur lequel l'annulation a été demandée. La meilleure façon de le faire est
    d'utiliser la méthode ThrowIfCancellationRequested. Une tâche
    annule de cette manière les transitions vers l'état Annulé, que le code appelant
    peut utiliser pour vérifier que la tâche a répondu à sa demande d'annulation
    .

http://msdn.microsoft.com/en-us/library/dd997396.aspx

Questions connexes