我有这个子:
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
这是由在parallel.for循环中运行的几个函数调用的。
问题是有时(完全随机)我收到错误:
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
在Dim ln = t_erori.Rows.Add
行。
我怀疑这是因为它试图将相同的行添加两次。 我怎样才能做到这一点?或者我可以使用其他方法来做到这一点?
我需要这个数据表,因为我的应用程序正在那里写一些结果,但是存储与parallel.for一起使用的结果的任何其他方法都可以。
答案 0 :(得分:2)
这是一种新的并行扩展疾病。您可以轻松编写不安全的代码。 DataTable的MSDN说:
线程安全
此类型对多线程安全 读操作。你必须同步 任何写操作。
您正在多个线程中执行非线程安全操作。您必须使用lock
或SpinLock(首选)或ReaderWriterLockSlim。
答案 1 :(得分:1)
解决此问题的天真方法是将所有内容包装在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
这里的问题是你已经有效地序列化了error_out
的执行,因为所有线程都必须争用同一个锁。最终结果是,这可能最终比同等的非并行版本运行得慢。
这里利用线程的最简单方法是将行添加到DataTable
的整个操作委托给一个工作线程,让主线程继续处理它正在做的事情,然后加入工作者当主线程请求完成操作时,通过Thread.Join
线程到主线程。