C#Parallel.ForEach-将空值随机写入DataRow

问题描述

为什么下面的代码随机地将空值写入DaTarow对象?

db.collection.update(
    {},{$addToSet:{'roles.$[r].aspirants':"Spider man"}},{ arrayFilters: [{ 'r.description.title': 'Role 1' }],new: true }
)

普通的for循环不会导致此问题-为什么,我的错误在哪里?

我的问题是-我可以修改并行循环内任何对象的属性吗?

ConcurrentDictionary<long,DaTarow> dRowDict = new ConcurrentDictionary<long,DaTarow>();
foreach (long klucz in data.Keys)
{
    DaTarow row = table.NewRow();
    dRowDict.TryAdd(klucz,row);
}
Parallel.ForEach(data.Keys,klucz =>
{
    Dane prz = data[klucz] as Dane;
    DaTarow dr = dRowDict[klucz];
    foreach (PropertyDescriptor prop in llProp)
    {
        dr[prop.Name] = prop.GetValue(prz) ?? dbnull.Value;
    }
});
foreach (DaTarow dRow in dRowDict.Values)
{
    table.Rows.Add(dRow);
    if (dRow["FILED"] == dbnull.Value)
    {
        MessageBox.Show("ERROR...NULL VALUE"); //why this happen?
    }
}

解决方法

仅当对象的类是线程安全的时才允许在并行循环内修改对象的属性。换句话说,如果该类是专门为允许同时从多个线程访问其成员而设计的。大多数类不是以这种方式设计的,而是假定它们一次将被一个线程访问。

根据我的经验,线程“不安全”被认为是默认值,因此,如果您在特定类的documentation中搜索线程安全部分,则不能找到它,您应该假定该类不是线程安全的。

同时从多个线程访问一个非线程安全的对象会导致“未定义的行为” 。这是“各种肮脏的东西” 的一个很好的正式同义词。它包括但不限于随机异常,损坏的状态,更新丢失,值被破坏,安全性受到破坏等。这些现象本质上是不确定的,并且通常是不可复制的。因此,这是极不明智的做法。

ADO.NET classes仅对多线程读取操作是线程安全的。这意味着多个线程同时读取其属性是安全的。但是,当线程正在修改ADO.NET对象时,其他任何线程都不能访问该对象,无论是读取还是修改它。