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

时间:2017-12-18 09:53:54

标签: c# parallel.foreach

我有一个平行的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检查过,最后一个元素数据可用,但仍然失败

任何人都可以帮我弄明白我的问题吗?

1 个答案:

答案 0 :(得分:4)

listSpacialRecords.Add(...);

我假设此方法不是显式线程安全的(默认情况下不会)。所有主题都与同一个listSpacialRecords进行对话。

你在Parallel.ForEach内执行此操作的那一刻,你有一个非常危险的线程竞争 - 如果两个线程同时调用.Add可能发生所有数量的坏事 - 包括数据丢失。

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

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

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