【发布时间】:2020-02-25 00:17:21
【问题描述】:
我正在编写一个应用程序,它在某些时候需要一个网格体并计算邻接索引。为此,我定义了一个 ConcurrentBag 对象数组,然后,在一个并行的 for 循环中,我只检查一些面,如果它们有任何邻接关系,我将索引添加到相应索引中的所述包中。即:
private bool parallelize = true;
private volatile ConcurrentBag<int>[] edge_adjacencies;
if (parallelize)
{
...
Parallel.For(0, face_count, compute_adjacency_single);
...
}
private void compute_adjacency_single(int cur_idx)
{
edge_adjacencies[cur_idx] = new ConcurrentBag<int>();
foreach(int test_idx in SOME_TEST_SPACE)
{
if (test_idx != cur_idx)
{
bool edge_adj, vertex_adj;
get_adjacency(cur_idx, test_idx, out edge_adj, out vertex_adj);
if (edge_adj && !collection_contains(edge_adjacencies[cur_idx], test_idx))
{
edge_adjacencies[cur_idx].Add(test_idx);
}
}
}
}
然后我对集合进行索引并检查每个集合的大小是否为 3(它们的大小都应该正好为 3):
//DEBUGGING
for (int i = 0; i < face_count; i++)
{
ConcurrentBag<int> cur = edge_adjacencies[i];
if (cur.Count != 3) Console.WriteLine("incorrect:" + i);
}
//DEBUGGING
这个过程的结果是不可预测的:有时我根本没有输出(所有的大小都是 3),有时我得到不正确的输出:
运行 1:
incorrect:3791
incorrect:3792
incorrect:3829
incorrect:3837
incorrect:4476
运行 5:
incorrect:2855
incorrect:2856
incorrect:2879
incorrect:2880
运行 8:
incorrect:3271
每运行 9 次左右就会给出不正确的结果。
作为参考,当我串行运行时,它每次都能完美运行。
我阅读了 MS 文档,它确实说 System.Collections.Concurrent 中的集合应该是线程安全的,但似乎情况并非如此。
为什么会发生这种情况,是否有防止这种情况的好方法?
【问题讨论】:
-
如果没有两个线程访问数组中的同一个索引,为什么还要使用
ConcurrentBag?有哪些并发访问? -
collection_contains是如何实现的?
标签: c# multithreading