web-dev-qa-db-fra.com

Jeton d'annulation dans le constructeur de tâches: pourquoi?

Certain System.Threading.Tasks.Task _ constructeurs prennent CancellationToken comme paramètre:

CancellationTokenSource source = new CancellationTokenSource();
Task t = new Task (/* method */, source.Token);

Ce qui me dérange, c’est qu’il n’ya aucun moyen de à l’intérieur du corps de la méthode d’obtenir réellement le jeton transmis (par exemple, rien de tel que Task.CurrentTask.CancellationToken). Le jeton doit être fourni via un autre mécanisme, tel que l'objet d'état ou capturé dans un lambda.

Alors à quoi sert la fourniture du jeton d'annulation dans le constructeur?

212
Colin

En transmettant ce jeton au constructeur de tâches, vous l'associez à cette tâche.

Citant Réponse de Stephen Toub de MSDN :

Cela présente deux avantages principaux:

  1. Si l'annulation est demandée pour le jeton avant le début de l'exécution de la tâche, celle-ci ne s'exécutera pas. Plutôt que de passer à Running, il passera immédiatement à Canceled. Cela évite les coûts d’exécution de la tâche si celle-ci était annulée en cours de toute façon.
  2. Si le corps de la tâche surveille également le jeton d'annulation et lève un OperationCanceledException contenant ce jeton (c'est ce que fait ThrowIfCancellationRequested,), alors lorsque la tâche voit que OperationCanceledException, il vérifie si le jeton de OperationCanceledException correspond au jeton de la tâche. Si tel est le cas, cette exception est considérée comme un accusé de réception de l'annulation coopérative et la tâche passe à l'état Annulé (plutôt qu'à l'état Défaillant).
245
Max Galkin

Le constructeur utilise le jeton pour la gestion des annulations en interne. Si votre code souhaite accéder au jeton, vous devez le transmettre à vous-même. Je recommande fortement de lire le livre sur la programmation en parallèle avec Microsoft .NET chez CodePlex .

Exemple d'utilisation de CTS du livre:

CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

Task myTask = Task.Factory.StartNew(() =>
{
    for (...)
    {
        token.ThrowIfCancellationRequested();

        // Body of for loop.
    }
}, token);

// ... elsewhere ...
cts.Cancel();
28
user7116

L'annulation n'est pas un cas simple, comme beaucoup pourraient le penser. Certaines des subtilités sont expliquées dans cet article de blog sur msdn:

Par exemple:

Dans certaines situations dans les extensions parallèles et dans d'autres systèmes, il est nécessaire d'activer une méthode bloquée pour des raisons qui ne sont pas dues à une annulation explicite par un utilisateur. Par exemple, si un thread est bloqué sur blockingCollection.Take () parce que la collection est vide et qu'un autre thread appelle ensuite blockingCollection.CompleteAdding (), le premier appel doit se réveiller et renvoyer une exception InvalidOperationException pour représenter un usage incorrect.

http://blogs.msdn.com/b/pfxteam/archive/2009/06/22/9791840.aspx

7
x0n