I am getting a hard to reproduce error in the following program in which a number of threads update a concurrent dictionary in parallel and the main thread displays the stat
As others have said, there is a race in the constructor of the internal class System.Linq.Buffer
, which is called by OrderBy
.
Here is the offending code snippet:
TElement[] array = null;
int num = 0;
if (collection != null)
{
num = collection.Count;
if (num > 0)
{
array = new TElement[num];
collection.CopyTo(array, 0);
}
}
The exception is thrown when item(s) are added to the collection
after the call to collection.Count
but before the call to collection.CopyTo
.
As a work around, you can make a "snapshot" copy of the dictionary before you sort it.
You can do this by calling ConcurrentDictionary.ToArray.
As this is implemented in the ConcurrentDictionary
class itself, it is safe.
Using this approach means you don't have to protect the collection with a lock which, as you say, defeats the purpose of using a concurrent collection in the first place.
while (!completed)
{
completed = t.Join(1);
var q =
from pair in wordFrequencies.ToArray() // <-- add ToArray here
orderby pair.Value descending, pair.Key
select new Tuple(pair.Key, pair.Value);
outputter.WriteBatch(q);
}