205 votes

Quand se CancellationTokenSource ?

La classe CancellationTokenSource est à usage unique et rapide coup d'oeil dans le réflecteur prouve l'utilisation de très probablement des ressources non managées KernelEvent. Il n'a pas d'outil de finalisation, donc si nous ne jetez pas les GC ne faire que des.

D'autre part, si vous regardez des échantillons sur MSDN Annulation de l'article tous les extraits de code, ne le faites pas, sauf un.

Il semble être difficile de trouver le bon endroit et le temps pour le faire dans le code.

  1. Vous ne pouvez pas envelopper le code de démarrage de votre tâche parallèle avec using si vous ne l'attendez pas. Et il est bon de disposer d'annulation que si vous n'attendez pas.
  2. Bien sûr, vous pouvez ajouter ContinueWith sur la tâche avec un Dispose appel, mais ce que le chemin à parcourir?
  3. Qu'en est annulable PLINQ des requêtes, qui ne se synchronisent pas en arrière, mais il suffit de ne somenthing à la fin? Disons - .ForaAll(x=> Console.Write(x))?
  4. Est-il réutilisable? Peut réutiliser le même pour plusieurs appels, puis débarrassez-vous avec le composant hôte, disons de contrôle d'INTERFACE utilisateur?

Parce qu'il n'a pas quelque chose comme Reset méthode pour nettoyer IsCancelRequested et Token déposée je suppose que c'est ni réutilisables, donc chaque fois que vous démarrez une tâche (ou une requête PLINQ), vous devez en créer un nouveau. Est-il vrai? Si oui, ma question est quelle est la bonne et de la stratégie recommandée pour traiter Dispose sur ceux de nombreux CancelationTokenSource instances?

103voto

Gruzilkin Points 101

Parler si c'est vraiment nécessaire de faire appel à Disposer sur CancellationTokenSource... j'ai eu une fuite de mémoire dans mon projet et il s'est avéré que CancellationToken(Source) était le problème...

mon projet a un service qui est constamment à la lecture de la base de données et déclenche des tâches différentes, et j'ai été en passant liée à l'annulation des jetons pour mes travailleurs, de sorte que même après qu'ils ont terminé le traitement de données, des jetons d'annulation n'étaient pas éliminés, qui a causé la fuite de mémoire dans mon cas.

et MSDN http://msdn.microsoft.com/en-us/library/dd997364.aspx en fait les etats clairement: Notez que vous devez Disposer d'appel sur le jeton lié à la source lorsque vous avez terminé avec elle. Pour un exemple plus complet, consultez Comment: Écouter pour de Multiples Demandes d'Annulation.

J'ai utilisé ContinueWith de le faire

31voto

Samuel Neff Points 35554

Vous devez toujours disposer CancellationTokenSource.

Comment éliminer cela dépend exactement sur le scénario. Vous proposer plusieurs scénarios différents.

  1. using ne fonctionne que lorsque vous êtes à l'aide de CancellationTokenSource sur certains travaux parallèles que vous êtes en attente. Si c'est votre senario, puis une grande, c'est la méthode la plus simple.

  2. Lors de l'utilisation de tâches, utiliser un ContinueWith de la tâche que vous avez indiqué pour éliminer CancellationTOkenSource.

  3. Pour plinq, vous pouvez utiliser using puisque vous êtes en cours d'exécution en parallèle, mais en attente sur l'ensemble du fonctionnement en parallèle des travailleurs à la fin.

  4. Pour l'INTERFACE utilisateur, vous pouvez créer un nouveau CancellationTokenSource pour chaque opération annulable qui n'est pas lié à un seul annuler déclencheur. Maintenir un List<IDisposable> et l'ajout de chaque source à la liste, l'élimination de tous, si votre composant est supprimé.

  5. Pour les threads, créer un nouveau fil qui relie tous les threads de travail et ferme la source unique lorsque tous les threads de travail terminé. Voir CancellationTokenSource, Quand à jeter?

Il y a toujours un moyen. IDisposable des instances doit toujours être éliminé. Les échantillons n'ont pas souvent parce qu'ils sont soit rapide des échantillons pour montrer de base de l'usage ou en raison de l'ajout dans tous les aspects de la classe démontré serait trop complexe pour un échantillon. L'échantillon est juste qu'un exemple, pas nécessairement (ou même généralement) la qualité de la production de code. Pas tous les échantillons sont acceptables pour être copié dans le code de production.

29voto

Bryan Crosby Points 4546

J’ai pris un coup de œil à ILSpy pour le mais je ne peux que trouver m_KernelEvent qui est en fait un , qui est une classe wrapper pour un objet WaitHandle. Il doit être traité correctement par le GC.

26voto

jlyonsmith Points 56

Cette réponse est encore à venir dans les recherches Google, et je crois que le votées réponse est de ne pas donner l'histoire complète. Après avoir regardé dans le code source pour CancellationTokenSource (CTS) et CancellationToken (CT) je crois que pour la plupart des cas d'utilisation de la séquence de code suivante est fine:

if (cancelTokenSource != null)
{
    cancelTokenSource.Cancel();
    cancelTokenSource.Dispose();
    cancelTokenSource = null;
}

L' m_kernelHandle champ interne mentionné ci-dessus est l'objet de synchronisation, la sauvegarde de l' WaitHandle propriété dans les deux CTS et CT classes. Il est instancié que si vous accédez à la propriété. Donc, sauf si vous utilisez WaitHandle pour certains de la vieille école de la synchronisation des threads dans votre Task appeler dispose aura aucun effet.

Bien sûr, si vous êtes en utilisant ce que vous devez faire ce qui est suggéré par les autres réponses ci-dessus et de retarder l'appel de Dispose jusqu'à WaitHandle opérations à l'aide de la poignée sont complètes, car, comme il est décrit dans la documentation de l'API Windows pour WaitHandle, les résultats ne sont pas définis.

2voto

Hans Passant Points 475940

Créer une nouvelle application Windows Forms à partir du modèle de projet. Déposez un bouton sur le formulaire et double-cliquez dessus. Faire ressembler à ceci:

    private void button1_Click(object sender, EventArgs e) {
        var t = new System.Threading.Thread(() => { });
        t.Start();
    }

Appuyez sur Ctrl+F5 pour démarrer. Démarrer + Exécuter, TaskMgr.exe onglet Processus. Afficher + de Sélectionner les Colonnes et cocher la case "Poignées". Observez la valeur de cette colonne pour la WindowsFormsApplication1.exe pendant que vous cliquez sur le bouton à plusieurs reprises.

La classe Thread ne dispose pas d'une méthode dispose ().

Nous allons travailler à partir de l'hypothèse qu'il en avait un. Quand voulez-vous l'appeler?


Lire plus à propos de la sagesse de chercher à disposer de dur-à-disposer les objets dans ce blog par Stephen Toub.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X