views:

38

answers:

2

I have this sub :

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

This is being called by several functions running in a parallel.for loop.

The problem is that sometimes (totally random) i get an error:

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

on the Dim ln = t_erori.Rows.Add line.

I suspect this is because it's trying to add the same row twice. How can i make this work ? Or what else method could I use to do this ?

I need this datatable because my app is writing some results in there, but any other method to store the results that works with parallel.for would be ok.

+1  A: 

This is a disease of new parallel extensions. You can easily write unsafe code. MSDN for DataTable says:

Thread Safety

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

You are performing not thread safe operation in several threads. You have to either use lock or SpinLock (preferred) or ReaderWriterLockSlim.

Andrey
Is there any kind of data structure that is thread safe for writing operations ?
Iulian
@Iulian http://stackoverflow.com/questions/2967057/is-it-possible-to-create-thread-safe-collections-without-locks
Andrey
the spinlock method is working fine, thanks
Iulian
A: 

The naive approach to fixing this is to wrap everything in a SyncLock block.

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 

The problem here is that you have effectively serialized the execution of error_out since all threads have to contend for the same lock. The end result is that this could end up running slower than the equivalent non-parallelized version.

The simplest way to take advantage of threads here is to delegate the entire operation of adding the rows to the DataTable to a worker thread and let the main thread continue on with what it was doing and then join the worker thread to the main thread via Thread.Join when it is time for the main thread to request completion of the operation.

Brian Gideon