Variable locale de méthode en cours de modification dans un Parallel.For.Dans quelle mesure est-ce sûr pour les threads ?

StackOverflow https://stackoverflow.com//questions/24039085

Question

J'ai cet extrait de code :

int totalData = result.Data.Count;
int count = 0;
Parallel.ForEach(result.Data, data =>
{
    try
    {
        EventRange importedEntity = ImportEntity(auxResult.EntityName, data);
        count++;
        EntityImported(importedEntity, count, totalData);
    }
    catch (Exception e)
    {
        exceptions.Enqueue(e);
    }
});

EntityImported est un événement qui devrait indiquer combien d'entités ont déjà été traitées et combien d'entités je dois traiter.Mes inquiétudes concernent la sécurité des threads lors de l'incrémentation du nombre à l'intérieur du lambda et les étapes que vous recommanderiez pour garantir que l'événement est toujours déclenché avec la valeur correcte de la variable count.

Était-ce utile?

La solution

Ce n'est pas du tout thread-safe pour le moment.

Vous pouvez utiliser Interlocked.Increment(ref count) à la place, mais c'est en général mieux vaut avoir une valeur "locale" pour chaque thread, et les additionner à la fin.De cette façon, vous n'avez besoin d'aucun flux de données inter-threads, autre que l'allocation des éléments à traiter.

Il y a une surcharge de Parallel.ForEach conçu uniquement dans ce but - regardez l'exemple en bas de la documentation, car il fait quelque chose très similaire à votre code.(Il maintient un décompte local, puis additionne les décomptes à la fin.) Malheureusement, cela n'aide pas dans votre cas particulier en raison de la façon dont vous devez déclencher un événement à chaque itération - mais généralement c'est une meilleure approche.

Dans ce cas, vous devez utiliser le résultat de Interlocked.Increment dans votre événement, soulevant le code :

Parallel.ForEach(result.Data, data =>
{
    try
    {
        EventRange importedEntity = ImportEntity(auxResult.EntityName, data);
        int newCount = Interlocked.Increment(ref count);
        EntityImported(importedEntity, newCount, totalData);
    }
    catch (Exception e)
    {
        exceptions.Enqueue(e);
    }
});

De cette façon, il y aura exactement un événement déclenché pour chaque compte (donc un avec 0, un avec 1, un avec 2, etc.).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top