2009-02-10 6 views

Répondre

53

Delegate.EndInvoke est documenté comme tu appelleras ce (c.-à-nécessaire - les fuites se produisent d'autre) - de msdn:

Note importante

N'importe quelle technique que vous utilisez, appelez toujours EndInvoke pour compléter votre asynchrone c tout.

Control.EndInvoke est OK ignorer pour et oublier le feu des méthodes - de msdn:

Vous pouvez appeler EndInvoke pour récupérer la valeur de retour du délégué, si neccesary, mais n'est pas requis.

Cependant - si vous utilisez Delegate.BeginInvoke et ne veulent pas le résultat, pensez à utiliser à la place ThreadPool.QueueUserWorkItem - ça va rendre la vie beaucoup plus facile, et éviter la douleur de IAsyncResult etc.

+0

Merci Marc, c'est ce qui a motivé la question - je regardais Richter et j'ai remarqué QueueUserWorkItem, et j'ai pensé "attendez, pourquoi est-ce que j'utilise BeginInvoke/EndInvoke ailleurs". – endian

+0

@endian - en effet: la plupart des utilisations de BeginInvoke peuvent être faites plus simplement avec ThreadPool; le BeginInvoke est peut-être utile pour faire quelques choses et les rassembler de nouveau après ... –

+0

Enlightened. Merci! – rpattabi

18

EndInvoke n'est pas facultatif.

Plus d'info here

+0

Merci Luca - réponse acceptée. – endian

+1

... pour les délégués, au moins ;-p –

+6

à partir de votre lien: "La seule exception documentée à la règle que je connaisse est dans Windows Forms, où vous êtes officiellement autorisé à appeler Control.BeginInvoke sans prendre la peine de appelez Control.EndInvoke. " – Avram

9

et appel EndInvoke n'est pas un appel optionnel, c'est une partie du contrat. Si vous appelez BeginInvoke, vous devez appeler EndInvoke.

Exemple classique de la raison pour laquelle cela est nécessaire. Il est très possible que le IAsyncResult retourné par BeginInvoke ait alloué des ressources qui lui sont attachées. Le plus souvent un WaitHandle de toutes sortes. Comme IAsyncResult n'implémente pas IDisposable, un autre emplacement doit être choisi pour libérer les ressources. Le seul endroit où le faire est EndInvoke. Je discute brièvement de ce problème dans l'article de blog suivant:

http://blogs.msdn.com/jaredpar/archive/2008/01/07/isynchronizeinvoke-now.aspx

+0

Merci Jared, très apprécié. – endian

4

EndInvoke n'est pas facultative, car elle est le lieu où des exceptions sont levées en cas de problème dans le traitement asyncronous. Quoi qu'il en soit, il ne devrait pas y avoir de fuite parce que si IAsyncResult détient une ressource native, il devrait implémenter correctement IDisposable et disposer de telles ressources lorsque le GC appelle son finaliseur.

2

C'est seulement facultatif si vous ne vous occupez pas de la mémoire de votre programme en grandissant. Le problème est que le GC conserve toutes les références dans votre thread, car vous pouvez appeler EndInvoke à un moment donné. J'irais avec la réponse de Marc, le pool de threads vous facilitera la vie. Cependant, vous devez faire attention si vous générez des threads à partir de vos threads, car il est limité dans le nombre de threads qu'il peut faire tourner.

3

Cela n'est pas facultatif car l'appel de BeginInvoke utilise un WaitHandle qui, à son tour, utilise un objet noyau qui maintient un compte pour le nombre de références qui lui sont associées.Appeler EndInvoke dispose gracieusement le descripteur qui décrémente ce compteur sur l'objet du noyau et lorsque ce compte atteint zéro, le gestionnaire d'objets du noyau le détruira.

2

Chaque réponse à cet article indique que EndInvoke() n'est pas facultatif. Cependant, j'ai trouvé le commentaire suivant très bien classé qui est la réponse acceptée sur ce thread SO:

"Notez que l'équipe Windows Forms a garanti que vous pouvez utiliser Control.BeginInvoke de manière 'fire and forget' - c'est à dire sans jamais appeler EndInvoke.Ce n'est pas le cas des appels asynchrones en général: normalement, chaque BeginXXX devrait avoir un appel EndXXX correspondant, généralement dans le rappel. "

What's the difference between Invoke() and BeginInvoke()

+0

IMHO, c'est dommage que 'Control.BeginInvoke' et' Delegate.BeginInvoke' partagent le même nom, car ils ont une sémantique totalement différente; à vrai dire, je suis curieux de savoir pourquoi les types de délégués définissent 'BeginInvoke' est une méthode d'instance, plutôt que d'avoir' Delegate.Bind (params) 'retourne un' MethodInvoker' [délégué zéro-argument] qui invoquerait le délégué avec les paramètres spécifiés, et qui pourraient être passés à une méthode ThreadPool.BeginInvoke. – supercat

+0

+1 pour cette distinction importante. Le commentaire du Skeet omniscient (cité ci-dessus) est très pertinent pour ceux qui considèrent les situations Control.InvokeRequired. –

Questions connexes