查询并行 foreach 结果导致 Null 引用错误

Querying parallel foreach result cause Null reference error

我有一个类似下面的并行 foreach 语句

  Parallel.ForEach(spacialRecords, (spacerecord) =>
                   {
                       List<MeterValue> dat = new List<MeterValue>();
                       var latitude = Geometry.Y;
                       var longitude = spacerecord.Geometry.X;
                       var timeStamp = spacerecord.Timestamp;

                       foreach (var wdItem in workingData)
                       {
                           RepresentationValue spaceMeteredValue = spacerecord.GetMeterValue(wdItem);
                           if (spaceMeteredValue != null && wdItem.Representation != null)
                           {
                               var objMeterValue = new MeterValue();
                               objMeterValue.key = wdItem.Representation.Code;
                               objMeterValue.value = spaceMeteredValue.Designator != null ? Convert.ToString(spaceMeteredValue.Designator) : "";
                               dat.Add(objMeterValue);
                           }
                       }

                       listSpacialRecords.Add(new
                       {

                           operationLogDataId = yieldMaster.OperationalLogDataModelResponse.Id,
                           order = deviceElement.Order,
                           totalDistanceTravelled = deviceElement.TotalDistanceTravelled,
                           totalElapsedTime = deviceElement.TotalElapsedTime,
                           uploadedOn = DateTime.Now.ToUniversalTime(),
                           collectedOn = timeStamp.ToUniversalTime(),
                           cropId = "8296e610-c055-11e7-851e-ad7650a5f99c",
                           productId = productid,
                           latitude = latitude,
                           longitude = longitude,
                           deviceConfigurationId = deviceElement.DeviceConfigurationId,
                           operationDataId = deviceElement.OperationDataId,
                           spatialRecords = dat,
                           depth = depth,
                           timeStamp = timeStamp,
                           totaldata = totalRecordCount

                       });

                   });

listSpacialRecords 是一个动态类型列表,我在 listSpacialRecords 中获取大量数据。所以我在这里做一些过滤,为此我添加了下面的代码

 listSpacialRecords = listSpacialRecords
                  .Skip(1)
                  .Aggregate(
                      listSpacialRecords.Take(1).ToList(),
                      (a, x) =>
                      {
                          if (x.timeStamp.Subtract(a.Last().timeStamp).TotalSeconds >= 10.0)
                          {
                              a.Add(x);
                          }
                          return a;
                      });

代码在 foreach 循环之外。当我执行此操作时,出现

之类的错误
Cannot perform run time binding on a null reference

但是当我删除并行并使用普通的 foreach 循环时,代码工作正常。

注意:我做了一个断点,我发现 listSpacialRecords 正确显示了所有记录,我用 quickwatch 检查了最后一个元素数据可用,但仍然失败

谁能帮我弄清楚我的问题是什么?

listSpacialRecords.Add(...);

我假设此方法不是明确线程安全的(默认情况下不会)。所有线程都在与同一个 listSpacialRecords.

对话

Parallel.ForEach 中执行此操作的那一刻,您将面临非常危险的线程竞争 - 如果两个线程同时调用 .Add 会出现所有问题可能发生 - 包括数据丢失。

因此:同步所有对此 Add 的调用。这个可以简单到:

var newValue = new {
    operationLogDataId = yieldMaster.OperationalLogDataModelResponse.Id,
    // etc etc...
};                           .
lock(listSpacialRecords) {
    listSpacialRecords.Add(newValue);
}

还有一个 dat.Add,但是这个 dat 是上下文绑定到每个调用的,所以不需要同步。