【问题标题】:What will happen if two references try to add data exactly same time in List<T> colletion如果两个引用尝试在 List<T> 集合中完全相同的时间添加数据会发生什么
【发布时间】:2012-02-29 10:17:35
【问题描述】:

检查此功能。

private static IEnumerable<string> FindAccessibleDatabases()
{
    var connectionStrings = new List<string>();
    Parallel.For(0, _connectionStringCollection.Count, (index, loopState) =>
    {
        try
        {
            using (var connection = new OleDbConnection(_connectionStringCollection[index]))
            {
                connection.Open();
                connectionStrings.Add(_connectionStringCollection[index]);
            }
        }
        catch (OleDbException)
        {
        }
        finally         
        {
           connection.Close();
        }
    });
    return connectionStrings.ToList();
}

我正在使用 Parallel.Foreach 并一次从多个数据库的列表中添加值。我可以使用 ConcurrentBag(检索数据时安全,但未提及添加),因为我只是将数据添加到列表中,可以使用 List。

现在如果两个线程同时尝试将数据添加到列表中会发生什么?

如果它会产生竞争条件,如果我使用 ConcurrentBag 会怎样?

谢谢, 奥姆卡尔

【问题讨论】:

  • 这被称为“竞争条件”。不要这样做。
  • 如果我两个尝试检索我可以理解,但同时添加也会发生?
  • 答案非常具体到它是什么类型的列表实现。看不出这怎么可能是 C# 和 Java。
  • @Affe 同意,这显然是 C#。对于ArrayList&lt;T&gt;,Java 中的答案恰好是相同的,但这是一个实现细节。

标签: c# list c#-4.0 collections


【解决方案1】:

您冒着发生未指明的坏事的风险,例如重复、未添加一项、破坏数据结构等。

The documentation 表示List&lt;T&gt; 的 Add 方法不是线程安全的(嗯,具体来说:

List&lt;T&gt; 可以同时支持多个阅读器,只要 集合未修改。通过集合枚举是 本质上不是线程安全的过程。在极少数情况下 枚举与一个或多个写访问竞争,这是唯一的方法 确保线程安全是在整个过程中锁定集合 枚举。允许多个人访问该集合 读写线程,你必须实现你自己的 同步。

)。因此,您需要使用lock statement 或其他形式的线程同步,或者您需要切换到线程安全的数据结构,例如System.Collections.Concurrent 命名空间中的某些东西。

如果使用 ConcurrentBag 的 Add 方法,则无需担心锁定问题。数据结构是明确的线程安全的。

【讨论】:

  • 在同样的场景下,如果我使用线程安全的数据结构,会发生这种情况吗? 1. 锁定列表 2. 添加第一项...同时将第二项放入队列 3. 解锁列表 4. 出列第二项
  • 线程安全的数据结构在读写时不需要锁。如果您对 System.Collections.Concurrent 的工作方式有疑问,我建议您单独提出或修改您的问题。
猜你喜欢
  • 1970-01-01
  • 2019-07-02
  • 1970-01-01
  • 2011-11-13
  • 2019-08-31
  • 1970-01-01
  • 2022-06-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多