2016-05-01 2 views
0

J'ai une classe Uploader avec une méthode - UploadAnnulation tâche de téléchargement async

public static int Upload(string endpoint,object objectToBeUploaded) 
    { 
     Source.Token.ThrowIfCancellationRequested(); 
     var repos = new UploadRepository(endpoint); 
     return repos.Upload(objectToBeUploaded); 
    } 

Le Source est un CancellationTokenSource statique disponible dans le projet.

J'ai aussi une liste de points de terminaison dont j'ai besoin de télécharger un certain object pour.

Le code dans le Form (c'est un très petit projet en utilisant WinForms) ressemble à ceci:

private async Task UploadObjectAsync(
      string endpoint, 
      object objectToBeUploaded) 
    { 
     try 
     { 
      int elementId = await Task.Factory.StartNew(
         () => Uploader.Upload(endpoint,objectToBeUploaded)); 
      //do something with the returned value.. 
     } 
     catch(OperationCanceledEception ex) 
     { 
      //handle the exception.. 
     } 
    } 

Et puis je mets le gestionnaire btnUpload.Click comme celui-ci, je peux donc utiliser plus tard:

this.btnUpload.Click += async (s, e) => 
{ 
    foreach(var endpoint in endpoints) 
    { 
     await UploadObjectASsync(endpoint,someObject); 
    } 
} 

Le problème est que chaque fois que je commence à télécharger à tous les points de terminaison (comment ils sont obtenus est sans importance) et je décide d'annuler le processus de téléchargement en utilisant Source.Cancel(); le premier UploadObjectAsync sera alwa ys passent par la vérification Source.Token.ThrowIfCancellationRequested(); dans la méthode Upload a déjà été passée. Le reste des tâches sera annulé normalement et géré avec élégance.

Comment est-ce que je peux restructurer ce code afin de m'assurer que le premier UploadObjectAsyncTask sera également annulé?

Il est à noter que je n'ai également pas accès au code source du processus de téléchargement lui-même (référence de service) - le repos.Upload(objectToBeUploaded) dans ma méthode Upload.

Répondre

1

Vous devez faire votre UploadRepository.Upload prendre un CancellationToken. Spécialement quand c'est celui qui fait l'opération d'E/S .. C'est quand le async/await est vraiment payant.

Cela vous aidera également à vous en débarrasser: Task.Factory.StartNew puisque la méthode Upload retournera la tâche déjà. Il n'y aura pas besoin de faire une tâche.

Dans votre configuration actuelle, si vous disposez de suffisamment de temps pour démarrer les tâches (et que vous passez par votre ThrowIfCancellationRequested), vous ne pourrez annuler aucun téléchargement. Même si cela prend 30 secondes.

En outre, vous pourriez être intéressé par: Task.Run

1

Il n'y a rien de pratique à faire. La méthode Upload ne prend pas de jeton. La première tâche a déjà passé le contrôle d'annulation au moment où vous appuyez sur le bouton d'annulation. Vous pouvez vous prouver que l'annulation est une question de synchronisation en ajoutant un sommeil de 10 secondes avant de lancer si l'appel annulé. Toutes les tâches seraient alors annulées.

0

Le problème est que vous ne pouvez pas arrêter le processus qui se produit dans la fonction Upload à moins qu'il vérifie l'état du CancellationToken tout se termine.

Donc ce que vous pouvez faire est d'interrompre le fil qui est en cours d'exécution en faisant quelque chose comme ceci:

int elementId = await Task.Factory.StartNew(() => 
{ 
    try 
    { 
    using (Source.Token.Register(Thread.CurrentThread.Interrupt)) 
    { 
     return Uploader.Upload(endpoint, objectToBeUploaded)); 
    } 
    } 
    catch (ThreadInterruptedException ex) 
    { 
    throw new OperationCanceledEception(ex) 
    } 
}, Source.Token); 

Utilisation de la fonction Source.Token.Register(delegate) vous provoquez le jeton d'appeler cette fonction au cas où le jeton est annulé. De cette façon, le thread qui exécute actuellement le uploadé devrait lancer une exception tout de suite.

Cette méthode ne fonctionne que si le thread entre WaitSleepJoin -State de temps en temps, car l'exception n'est levée que si le thread est dans cet état. Jetez un oeil à la documentation de la fonction Thread.Interrupt. L'alternative est d'utiliser Thread.Abort et ThreadAbortedException. Cela détruira votre thread dans tous les cas, mais cela peut corrompre l'état interne de votre service, car les verrous des threads ne seront pas libérés correctement. Alors soyez très prudent en utilisant cette méthode.

+0

Il est à noter que ce n'est pas vraiment conseillé. –

+0

Ouais ... mais interrompre le fil devrait être relativement sûr. – Nitram

+0

Oui. Le code de téléchargement doit toujours être changé. Bien que ce soit hors de son contrôle, alors ce serait le chemin à parcourir. –