Maison >développement back-end >C++ >Comment gérer la «collection a été modifiée; l'opération d'énumération peut ne pas exécuter« Erreurs dans des environnements multithreads?

Comment gérer la «collection a été modifiée; l'opération d'énumération peut ne pas exécuter« Erreurs dans des environnements multithreads?

DDD
DDDoriginal
2025-02-02 03:46:10471parcourir

How to Handle

Adressant "Collection modifiée: l'opération d'énumération peut échouer" Erreurs

La collection d'erreur "a été modifiée; l'opération d'énumération peut ne pas s'exécuter" survient lorsqu'une collection est modifiée tout en étant itérée, conduisant à un comportement imprévisible. Cela se produit généralement dans des scénarios multithread où plusieurs threads accèdent et modifient simultanément la même collection.

Cette erreur spécifique se manifeste dans la méthode NotifySubscribers(), où le dictionnaire subscribers est accessible dans une boucle foreach. Les modifications simultanées de ce dictionnaire (par exemple, les abonnements aux clients ou les désabonnements) invalident l'énumération.

Solution: implémentation de la sécurité du thread

Pour résoudre ce problème, la sécurité du fil pour le dictionnaire subscribers est cruciale. Deux approches sont recommandées:

  1. en utilisant ConcurrentDictionary: Remplacez le dictionnaire standard par ConcurrentDictionary<TKey, TValue>. Cette structure de données est intrinsèquement filiale, empêchant l'erreur.

  2. Création d'une copie pour itération: Avant la boucle foreach, créez une copie des valeurs du dictionnaire subscribers à l'aide de subscribers.Values.ToList(). Cela crée un instantané qui n'est pas affecté par les modifications ultérieures du dictionnaire d'origine, garantissant une énumération sûre.

Exemples de code:

Voici la méthode NotifySubscribers() modifiée pour utiliser ConcurrentDictionary:

<code class="language-csharp">public void NotifySubscribers(DataRecord sr)
{
    foreach (Subscriber s in subscribers.Values) // subscribers is now a ConcurrentDictionary
    {
        try
        {
            s.Callback.SignalData(sr);
        }
        catch (Exception e)
        {
            DCS.WriteToApplicationLog(e.Message, System.Diagnostics.EventLogEntryType.Error);
            UnsubscribeEvent(s.ClientId);
        }
    }
}</code>

Et voici la version utilisant ToList() pour créer une copie sûre:

<code class="language-csharp">public void NotifySubscribers(DataRecord sr)
{
    foreach (Subscriber s in subscribers.Values.ToList())
    {
        try
        {
            s.Callback.SignalData(sr);
        }
        catch (Exception e)
        {
            DCS.WriteToApplicationLog(e.Message, System.Diagnostics.EventLogEntryType.Error);
            UnsubscribeEvent(s.ClientId);
        }
    }
}</code>

En mettant en œuvre l'une ou l'autre de ces solutions, vous assurez la sécurité des threads et empêchez l'erreur "Collection a été modifiée ...", conduisant à un code plus robuste et fiable.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn