c# - Parallel.For 和 ConcurrentBag 给出不可预测的行为

标签 c# multithreading

我正在编写一个应用程序,该应用程序在某些时候采用网格体并计算邻接索引。为此,我定义了一个 ConcurrentBag 对象数组,然后,在并行 for 循环中,我只检查一些面,如果它们有任何邻接,我将索引添加到相应索引中的所述包中。 IE。:

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 中的集合应该是线程安全的,但似乎并非如此。

为什么会发生这种情况,有没有好的方法可以防止这种情况发生?

最佳答案

唔。这是一个猜测 - 但我不认为这样做 edge_adjacencies[cur_idx] = ..compute_adjacency_single是线程安全的。
CuncurrentBag<int>是非常线程安全的,但保存它们实例的数组不是。

我会使用 ConcurrentDictonary而不是数组。

关于c# - Parallel.For 和 ConcurrentBag 给出不可预测的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58612830/

相关文章:

c# - HtmlAgilityPack - 找不到文件

java - volatile 在 Java 的单线程应用程序中有用吗?

c - 具有结构数组的线程返回 SIGSEGV (段错误错误)?

c++ - C++11 中的线程不在类成员中

python - 向其他QThread发送消息

c# - JSON 反序列化 - 处理可以是数组的属性

c# - 使用 BlockingCollection<T> 作为单一生产者、单一消费者 FIFO 查询是否好?

c# - 计算分层对象列表中所有项目的方法

c# - 如果用户在hangman c#中猜测正确,如何显示用户的输入

java - 如何在Java代码中启动一组线程