27 votes

Les gestionnaires d'événements ne sont pas sûrs pour les threads?

J'ai donc lu cela au lieu d'appeler un événement directement avec

 if (SomeEvent != null)
   SomeEvent(this, null);
 

je devrais faire

 SomeEventHandler temp = SomeEvent;
if (temp != null)
    temp(this, null);
 

Pourquoi cela est-il ainsi? Comment la deuxième version devient-elle thread-safe? Quelle est la meilleure pratique?

24voto

Marc Gravell Points 482669

L'OMI, de l'autre des réponses manquer un détail clé - que les délégués (et, par conséquent, événements) sont immuables. La signification de ceci est que vous abonner ou vous désabonner d'un gestionnaire d'événement n'est pas simplement ajouter/supprimer de la liste plutôt, il remplace la liste avec un nouveau avec un en plus (ou en moins) point sur elle.

Depuis références sont atomiques, cela signifie que, au point de le faire:

var handler = SomeEvent;

vous avez maintenant une rigide instance qui ne peuvent pas changer, même si dans la prochaine picoseconde un autre thread se désinscrit (provoquant l' effectif des champs d'événements deviennent null).

Afin de tester la valeur null et à l'appeler, et tout est bien. Note bien sûr qu'il y a encore de la confusion scénario de l'événement qui a été soulevée sur un objet qui pense qu'il désabonné une picoseconde il y!

13voto

Nigel Thorne Points 6412

Les événements sont vraiment sucre syntaxique sur une liste de délégués. Lorsque vous appelez le cas, c'est vraiment une itération sur cette liste et de l'invocation de chaque délégué avec les paramètres que vous avez passé.

Le problème avec les threads, c'est qu'ils pourraient être l'ajout ou la suppression d'éléments de cette collection par abonnement/désabonnement. S'ils le faire alors que vous êtes en itérant la collection cela va poser des problèmes (je pense à une exception est levée)

Le but est de copier la liste avant de l'itération, donc vous êtes protégé contre les modifications de la liste.

Remarque: cependant, Il est maintenant possible pour votre auditeur à être invoquée, même après que vous vous êtes désabonné, de sorte que vous devriez assurez-vous de gérer cela dans votre code d'écouteur.

5voto

Mitch Wheat Points 169614

La meilleure pratique est la deuxième forme. La raison en est qu'un autre thread peut annuler ou modifier SomeEvent entre le test ' if ' et l'appel.

2voto

Brian ONeil Points 3012

Voici un bon article sur les événements .NET et les conditions de concurrence avec des threads. Il couvre certains scénarios courants et contient de bonnes références.

J'espère que cela t'aides.

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