【问题标题】:.NET CLR - Object Reference Synchronization.NET CLR - 对象引用同步
【发布时间】:2011-08-19 14:42:11
【问题描述】:

在多线程 .NET 应用程序中,

假设第一个线程正在写入一个列表 第二个线程正在清除所有项目。 第三个线程正在从列表中读取。

如果第二个和第三个线程在 CLR 级别上“真正”同时访问同一个列表对象会发生什么。我不是指 .NET 同步对象和锁定机制。

我的意思是,当 CLR 从引用(通过第 3 个线程)访问列表项时,如果引用指向的列表发生变化(通过第 2 个线程)会发生什么?

【问题讨论】:

    标签: .net multithreading thread-safety clr


    【解决方案1】:

    坏东西。

    这种类型的公共静态(在 Visual Basic 中为共享)成员是线程安全的。 不保证任何实例成员都是线程安全的。

    只要不修改集合,List<T> 可以同时支持多个读取器。通过集合进行枚举本质上不是线程安全的过程。在枚举与一个或多个写访问竞争的极少数情况下,确保线程安全的唯一方法是在整个枚举期间锁定集合。要允许集合被多个线程访问以进行读写,您必须实现自己的同步。

    【讨论】:

      【解决方案2】:

      它爆炸了。 InvalidOperationException 被抛出,因为枚举发生了变化。

      【讨论】:

      • 没有使用枚举。考虑简单地访问列表的第一项
      【解决方案3】:

      如果您倾向于更新列表并在多线程代码中读取它,那么可能会发生很多故障,例如,假设我们有以下场景:

      //c#
      List<object> myList...
      
      //at reading thread
      if (myList.Count > 0)
      {
          object item = myList[0];//get the item at the first index of the collection.
      }
      
      //at writing thread
      myList.Clear();
      

      写入线程在更新列表的同时读取线程正在从列表中读取,因此假设执行如下:
      阅读器线程检查集合中是否有项目,并发现其中有一些项目“.Count &gt; 0 为真”,因此继续执行,但在到达下一行之前,线程上下文切换 通过切换到编写器线程暂停读取器线程,因此它执行其代码myList.Clear();,此时线程上下文切换回读取器线程以继续执行,因此它尝试获取myList[0],但是那个时候,作者线程的集合是空的,所以它将失败并出现异常IndexOutOfRange..

      另一种情况,如果读取器线程使用foreach 抛出集合,而写入器线程只是更改了集合“添加/删除”了一些项目,它会再次抛出异常,因为循环时集合发生了变化。

      因此,在与列表交互时,您必须使用一些同步机制,例如 C# 中的 lock 或使用 Monitor 类。但是,如果您使用的是 4.0,则可以关闭以使用 ConcurrentCollection 而不是普通列表,它们是线程安全的集合。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-21
        • 2016-10-12
        • 2017-03-31
        • 1970-01-01
        相关资源
        最近更新 更多