Creating Race Conditions
A common trick with LINQ is to use the where clause to filter items from the source data while some external value has a specified value and is modified inside the where clause itself. This presents a data race with PLINQ because multiple Tasks can be reading and modifying the value at once.
Example
The following example uses a shared value to limit the number of items that the where clause filters for processing and so suffers from a race condition:
using System;
using System.Linq;
namespace Creating_Race_Conditions {
class Creating_Race_Conditions {
static void Main(string[] args) {
// create some source data
int[] sourceData = new int[10000];
for (int i = 0; i < sourceData.Length; i++) {
sourceData[i] = i;
}
// create a counter - this will be shared
int counter = 1000;
// create a plinq query that uses the shared value
var result = from e in sourceData.AsParallel()
where (counter-- > 0)
select e;
Console.WriteLine("Expected {0} items", counter);
Console.WriteLine("Got {0} items", result.ToArray().Length);
}
}
}
Solution:
Perform the filter sequentially before processing the data in parallel. Or find a PLINQ method that will work safely with multiple threads (e.g., the Take() method would be a suitable alternative to the example code for this problem). As a last resort, use a synchronization primitive to control access to the shared value.In my next blog i will describe some advanced synchronization primitives that will solve the race contition