多数のスレッドが並行辞書を並行して更新し、メインスレッドが一定の時間間隔の後、すべての更新スレッドが完了するまで辞書の状態をソートされた順序で表示する次のプログラムで、再現が困難なエラーが発生しています。
public void Function(IEnumerable<ICharacterReader> characterReaders, IOutputter outputter)
{
ConcurrentDictionary<string, int> wordFrequencies = new ConcurrentDictionary<string, int>();
Thread t = new Thread(() => UpdateWordFrequencies(characterReaders, wordFrequencies));
bool completed = false;
var q = from pair in wordFrequencies orderby pair.Value descending, pair.Key select new Tuple<string, int>(pair.Key, pair.Value);
t.Start();
Thread.Sleep(0);
while (!completed)
{
completed = t.Join(1);
outputter.WriteBatch(q);
}
}
関数には、文字ストリームと出力子のリストが与えられます。この関数は、各文字ストリームから読み取られた単語の単語頻度の同時辞書を(並列に)維持します。単語は新しいスレッドによって読み込まれ、メインスレッドは、すべての入力ストリームが読み込まれるまで、1ミリ秒ごとに辞書の現在の状態を(ソートされた順序で)出力します(実際には、出力は10秒ごとのようになります。ただし、エラーは非常に小さい値でのみ表示されるようです)。WriteBatch関数は、コンソールに書き込むだけです。
public void WriteBatch(IEnumerable<Tuple<string, int>> batch)
{
foreach (var tuple in batch)
{
Console.WriteLine("{0} - {1}", tuple.Item1, tuple.Item2);
}
Console.WriteLine();
}
ほとんどの実行は問題ありませんが、WriteBatch関数のforeachステートメントで次のエラーが発生することがあります。
「未処理の例外:System.ArgumentException:インデックスが配列の長さ以上であるか、ディクショナリ内の要素の数が、インデックスから宛先配列の最後までの使用可能なスペースよりも大きいです。」
スレッドの更新を開始した後、表示ループを開始する前にメインスレッドが短時間スリープすると、エラーは解消されたように見えます。また、orderby句が削除され、辞書がlinqクエリで並べ替えられていない場合も、なくなるようです。説明はありますか?
foreach (var tuple in batch)
WriteBatch関数のステートメントはエラーを出します。スタックトレースは次のとおりです。
未処理の例外:System.ArgumentException:インデックスが配列の長さ以上であるか、ディクショナリ内の要素の数が、インデックスから宛先配列の最後までの使用可能なスペースよりも大きいです。System.Linq.Buffer1..ctor(IEnumerable1 source)atSystem.Linq.OrderedEnumerable1のSystem.Collections.Concurrent.ConcurrentDictionary2.System.Collections.Generic.ICollection> .CopyTo(K eyValuePair2 [] array、Int32 index)で。 d__0.MoveNext()at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()at MyProject.ConsoleOutputter.WriteBatch(IEnumerable1 batch)in C:\ MyProject \ ConsoleOutputter.cs:line 10 at MyProject.Function(IEnumerable1 characterReaders、IOutputter outputter)