下面的代码有两个问题:
- 在锁内使用 yield return 是否合法?
当我们在 foreach 循环中循环 Get() 方法时,锁会发生什么?
public IEnumerable<SomeObject> Get() { _lock.EnterReadLock(); try { foreach (var item in _dictionary) { yield return new SomeObject(item.Key, item.Value); } } finally { _lock.ExitReadLock(); } } private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
有限允许。当您在 foreach 循环中绕过这样的序列时,将在进入循环之前获取锁,并在退出后释放。此外,锁将在循环中的任何中断时释放。
然而,IEnumerable 的使用并不局限于简单的循环。使用锁时,将锁保持一小段时间总是很重要的 - 在这里您可以将其拉伸一段时间,超出您的控制!这样你就可以轻松打出直到僵局。
通常最好获取锁下数据的副本,并在将来使用它:
甚至像这样:
看,这在语言层面是可能的——编译器无法检查。但不建议这样做。
一般规则是这样的:你应该避免在锁下调用别人的代码。假设您违反了规则并
yield在禁令下执行。同时,客户端代码可以调用另一个线程(如果我们没有多线程,那么我们仍然不需要锁,对吧?)。如果
Process在方法中取了同一个锁,就会出现死锁,代码会挂起:Process一直等到锁被释放,阻塞代码从yield返回(也就是循环的下一次迭代) .