Reputation: 21931
I have a parallel foreach statement like below
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 is a dynamic type list and i am getting a huge number of data in listSpacialRecords. So here i am doing some filtering, for that i have added the below code
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;
});
The code is outside of foreach loop. And when i execute this I am getting error like
Cannot perform run time binding on a null reference
But when i remove the parallel and use normal foreach loop the code works fine.
Note : I made a break point over and I found listSpacialRecords shows all the records properly, I have checked with quickwatch and upto last element data is available but still it fails
Can anyone help me to figure out what i the issue?
Upvotes: 3
Views: 2994
Reputation: 1062600
listSpacialRecords.Add(...);
I'm assuming that this method is not explicitly thread-safe (it won't be by default). All the threads are talking to the same listSpacialRecords
.
The moment you do this inside Parallel.ForEach
, you have a very risky thread race - if two threads are calling .Add
at the same time, all number of bad things can happen - including data loss.
So: synchronize all calls to this Add
. This could be as a simple as:
var newValue = new {
operationLogDataId = yieldMaster.OperationalLogDataModelResponse.Id,
// etc etc...
}; .
lock(listSpacialRecords) {
listSpacialRecords.Add(newValue);
}
There's also a dat.Add
, but this dat
is context-bound to each call, so shouldn't need synchronization.
Upvotes: 8