【发布时间】:2016-03-25 10:43:00
【问题描述】:
我正在使用一个线程方数据模型,它使用它的自定义数据模型。数据模型的层次结构如下:
型号
---表格(表格类型)
-----行(行类型)
-------细胞(细胞类型)
Table 与 DataTable 一样具有属性 Rows,我必须在多个任务中访问此属性。现在我需要表中的一行,该行具有指定值的列值。
为此,我创建了一个具有 lock 语句的方法,使其只能从一个线程访问一次。
public static Row GetRowWithColumnValue(Model model, string tableKey, string indexColumnKey, string indexColumnValue)
{
Row simObj = null;
lock (syncRoot)
{
SimWrapperFromValueFactory wrapperSimSystem = new SimWrapperFromValueFactory(model, tableKey, indexColumnKey);
simObj = wrapperSimSystem.GetWrapper(indexColumnValue);
}
return simObj;
}
为了创建表中某一列的查找,我创建了一个方法,该方法总是尝试创建行的副本以避免集合修改异常:
Private Function GetTableRows(table As Table) As List(Of Row)
Dim rowsList As New List(Of Row)(table.Rows) 'Case 1
'rowsList.AddRange(table.Rows) 'Case 2
' Case 3
'For i As Integer = 0 To table.Rows.Count - 1
'rowsList.Add(table.Rows.ElementAt(i))
'Next
Return rowsList
End Function
但其他线程可以修改表(例如添加、删除行或更新任何行中的列值)。我得到以下“集合修改异常”:
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)
我无法将此第三方库修改为并发集合和多个项目之间共享的相同数据模型。
问题:我正在寻找一种解决方案,该解决方案允许我允许此集合上的多个读者,或者它在另一个线程中修改.. 是否有可能获取集合的副本而不会出现异常??
在SO线程下引用但没有找到确切的解决方案:
Lock vs. ToArray for thread safe foreach access of List collection
Can ToArray() throw an exception?
Is returning an IEnumerable<> thread-safe?
【问题讨论】:
-
如果我理解正确,您可以创建一个包含行的新列表并使用该行。
var rows = new List<Row>(GetTableRows()); -
您不能“锁定”没有内置支持的集合(通过
SyncRoot或类似方法)。此外,即使您成功拍摄了数据快照(通过重试完整副本,直到最终无一例外地获得一个),您如何确保另一个线程没有通过修改行/单元格值来产生损坏?没有表本身所做的并发检查。这是一个棘手的情况。 -
@Domysee:我已经用 3 个实现对其进行了测试,我目前正在按照您的建议进行操作,但它也在内部使用 GetEnumerator 方法,这会导致问题。
-
@NiranjanKala,
table.Rows到底是什么?是List(Of Row)吗?如果是这样,我建议使用CopyTo方法,因为它绕过枚举器并且只访问2 个字段:_items和_count,每个字段都访问一次,因此竞争的概率远低于涉及GetEnumerator的任何内容。如果您想彻底,您还可以打破反射并检查操作前后的_version字段,以确保在您复制时列表没有被修改。如果您觉得这听起来很明智,请告诉我,我会将其编造成答案。 -
当然请记住,这只会解决表级别的竞争问题(即保护您免受另一个线程添加、删除或交换行的影响)。如果行和单元格不是不可变的并且可以被另一个线程改变,那么您可能仍然不走运,因为您永远无法获得快照数据一致性保证。
标签: c# multithreading multitasking