2010-07-13 6 views
1

Je cette sous:ajouter des lignes à une table de données avec Parallel.For

Private Sub error_out(ByVal line As Integer, ByVal err_col As Integer, ByVal err_msg As String) 

      Dim ln = t_erori.Rows.Add 
      ln.Item(0) = line 
      ln.Item(err_col) = err_msg 
      ln.Item(3) = err_col 
    End Sub 

Ceci est appelé par plusieurs fonctions en cours d'exécution dans une boucle de Parallel.For.

Le problème est que parfois (totalement aléatoire) je reçois une erreur:

Index was out of range. Must be non-negative and less than the size of the collection. 
Parameter name: index 

sur la ligne Dim ln = t_erori.Rows.Add.

Je suppose que c'est parce qu'il essaie d'ajouter deux fois la même ligne. Comment puis-je faire ce travail? Ou quelle autre méthode pourrais-je utiliser pour faire ceci?

J'ai besoin de cette datatable parce que mon application écrit des résultats là-dedans, mais toute autre méthode pour stocker les résultats qui fonctionnent avec parallel.for serait ok.

Répondre

2

Ceci est une maladie de nouvelles extensions parallèles. Vous pouvez facilement écrire du code dangereux. MSDN pour DataTable dit:

Thread Safety

This type is safe for multithreaded read operations. You must synchronize any write operations.

Vous effectuez pas thread opération sécurité dans plusieurs threads. Vous devez soit utiliser lock ou SpinLock (préféré) ou ReaderWriterLockSlim.

+0

Existe-t-il un type de structure de données sans thread pour les opérations d'écriture? – Iulian

+0

@Iulian http://stackoverflow.com/questions/2967057/is-it-possible-to-create-thread-safe-collections-without-locks – Andrey

+0

la méthode spinlock fonctionne bien, merci – Iulian

1

L'approche naïve pour résoudre ce problème consiste à tout emballer dans un bloc SyncLock.

Private Sub error_out(ByVal line As Integer, ByVal err_col As Integer, ByVal err_msg As String) 

    SyncLock t_erori 
    Dim ln = t_erori.Rows.Add 
    ln.Item(0) = line 
    ln.Item(err_col) = err_msg 
    ln.Item(3) = err_col 
    End SyncLock 

End Sub 

Le problème ici est que vous avez effectivement sérialisé l'exécution de error_out puisque tous les fils doivent faire la même serrure. Le résultat final est que cela pourrait finir par courir plus lentement que la version équivalente non-parallélisée. La manière la plus simple de tirer parti des threads est de déléguer toute l'opération d'ajout des lignes au DataTable à un thread de travail et de laisser le thread principal continuer avec ce qu'il faisait, puis de joindre le thread de travail au thread principal via Thread.Join lorsqu'il est temps pour le thread principal de demander l'achèvement de l'opération.

Questions connexes