【发布时间】:2018-09-29 03:29:43
【问题描述】:
给定示例类:
internal Stuff<T> : IEnumerable<T> where T : Foo
{
private readonly object Sync = new object();
private readonly T[] TObjects;
public IEnumerator<T> GetEnumerator()
{
lock(Sync)
using (IEnumerator<T> safeEnum = TObjects.AsEnumerable().GetEnumerator())
while (safeEnum.MoveNext())
yield return safeEnum.Current;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
//other things
}
如果我在 foreach 循环中迭代这个类,整个 foreach 循环就会被对象的锁定方案锁定。 我的问题是,如果我在 linq 查询中使用它会发生什么,例如:
Stuff stuff = new Stuff() { /*some foos*/ };
var things = stuff.Where(/*some predicate*/);
foreach(Foo foo in things)
{
//am i locked?
}
foreach(Foo foo in stuff.Where(/*some predicate*/))
{
//am i locked?
}
所以归结为,查询链接在后台是如何工作的?
【问题讨论】:
-
我被屏蔽了吗?其实不是。如果您有对该对象的引用,并且没有其他代码拥有它,那么您将永远不会被阻止。如果你迭代它(在一个线程上说 T1)并且其他一些代码可以访问完全相同的对象并在另一个线程上迭代它,它将被阻塞,直到 T1 完成迭代。这里重要的部分是对象被锁定而不是类。
-
@CodingYoshi 已锁定,未阻止。锁定机制传播到 foreach 循环中,我问它是否也通过对对象进行的 LINQ 查询传播到 foreach 循环中。
-
LINQ 是基于它的抽象,所以是的,同样的规则也适用。
-
对于您发布的代码,您不需要锁,因为多个线程可以只读访问数据结构。如果您进行一些修改,那么确保线程安全很重要,但我宁愿为该用例使用并发收集
-
Internally Linq Where 只是根据谓词减少集合,你的两个代码sn-ps没有区别,当多个线程访问数据结构时,锁会起作用,但不需要只读枚举器
标签: c# linq locking ienumerable