C# Parallel.For和ConcurrentBag提供不可预测的行为
我正在编写一个应用程序,在某个时候,它会获取一个网格体并计算邻接索引。为此,我定义了一个ConcurrentBag对象数组,然后,在并行for循环中,我只需检查一些面,如果它们有任何邻接,我将索引添加到相应索引中的所述包中。即:C# Parallel.For和ConcurrentBag提供不可预测的行为,c#,multithreading,C#,Multithreading,我正在编写一个应用程序,在某个时候,它会获取一个网格体并计算邻接索引。为此,我定义了一个ConcurrentBag对象数组,然后,在并行for循环中,我只需检查一些面,如果它们有任何邻接,我将索引添加到相应索引中的所述包中。即: private bool parallelize = true; private volatile ConcurrentBag<int>[] edge_adjacencies; if (parallelize) { ... Parallel.
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);
}
}
}
}
运行5:
incorrect:2855
incorrect:2856
incorrect:2879
incorrect:2880
运行8:
incorrect:3271
大约每运行9次,就会给出不正确的结果
作为参考,当我以串行方式运行时,它每次都能完美地工作
我阅读了MS文档,它确实说System.collections.Concurrent中的集合应该是线程安全的,但看起来情况并非如此
为什么会发生这种情况,有没有一种很好的方法来防止这种情况发生?嗯。这是一个猜测——但我不认为在
计算邻接中这样做是线程安全的
CuncurrentBag
是非常线程安全的,但是保存它们的实例的数组却不是
我会使用一个而不是数组。我会使用一个锯齿状数组来确定(或者如果你不觉得很难实现的话,使用一个扁平的1D数组),但这只是我的偏好,因为我得到的数据或多或少是按索引排序的
我认为问题在于使用bool-edge_-adj,vertex_-adj时存在竞争条件代码>。创建一个数组或任何您更喜欢的线程安全数据结构,并使用get_adjacence
函数填充它,这样您就可以访问布尔值,而不会让线程覆盖彼此的值。我来看看是否可以使用字典实现,尽管每个线程都从该数组中访问一个唯一的元素……它必须是线程安全的集合类型,“普通”指令也会有同样的问题。问题不在于cur_idx
的唯一性,而在于(我怀疑)数组索引方法的实现。如果每个线程访问数组中的不同索引,则不应该存在线程问题。@Rotem这与您所说的问题不同。访问数组中的包-功能类似于get方法。get方法返回特定索引处的包。get方法不是线程安全的。这正是我所说的。假设没有线程访问数组中的同一索引,那么访问是安全的。如果数组中从来没有任何两个线程访问同一索引,为什么还要使用ConcurrentBag
?有什么并发访问?如何实现collection\u contains
?如果线程从不访问同一数组元素,它们将如何覆盖彼此的值?@Rotem,因为没有数组!线程试图同时访问布尔边、顶点代码>变量显示这可能吗?这些是局部变量。它们只存在于线程本地foreach
循环中。因为它们是通过引用get_adjacency
方法传递的,所以会覆盖相同的地址。但地址是局部变量。每个线程的地址都不同。甚至可能在每个线程中循环的不同迭代中。
incorrect:2855
incorrect:2856
incorrect:2879
incorrect:2880
incorrect:3271