更新对不可变对象的引用的首选方法是什么?

use*_*470 3 c# multithreading synchronization immutability

如果我们有一个像ImmutableList()这样的不可变对象.在多线程环境中使用此对象的首选方法是什么?

例如

public class MutableListOfObjects()
{
   private volatile ImmutableList objList;

   public class MutableListOfObjects()
   {
       objList = new ImmutableList();
   }

   void Add(object o)
   {
      // Adding a new object to a list will create a new list to ensure immutability of lists.

      // Is declaring the object as volatile enough or do we want to
      // use other threading concepts?
      objList = objList.Add(o);
   }

   // Will objList always use that lest version of the list
   bool Exist(object o)
   {
      return objList.Exist(o);
   }
}
Run Code Online (Sandbox Code Playgroud)

声明参考volatile是否足以实现所需的行为?或者最好使用其他线程功能?

Mar*_*ell 6

"首选"是语境.在最简单的方法是使用一个lock,在这将非常有效地完成这项工作大部分情况下.如果你有充分的理由认为这lock是一个问题,那么Interlocked很有用:

bool retry;
do {
    var snapshot = objList;
    var combined = snapshot.Add(o);
    retry = Interlocked.CompareExchange(ref objList, combined, snapshot)
              != snapshot;
} while(retry);
Run Code Online (Sandbox Code Playgroud)

这基本上适用于乐观但经过检查的路径:大多数情况下,它只会经历一次.偶尔有人会改变objList我们不看的价值- 那没关系,我们再试一次.

然而,有些人真正知道他们在谈论什么,有预先实现的线程安全列表等.考虑使用ConcurrentBag<T>等.或者只是List<T>一个lock.

  • @ user2377470"Interlocked.CompareExchange"的意思是它完全是原子的; 比如两个线程A和B同时运行`snapshot =`和`combined =`行.当他们调用`CompareExchange`时,**他们两个都不可能成功.其中至少有一个会失败并且必须重试.请注意,我在那里使用的`CompareExchange`版本是"作为一个原子操作,将当前值与此预期值进行比较;如果相同,则将其替换为此新值;否则***不执行任何操作***;无论哪种方式,告诉我这个领域是什么" (2认同)