yield 在 lock 语句中返回
如果我在锁定语句中有一个yield return,那么锁会在每个yield上被取出(在下面的示例中为5次),还是仅对列表中的所有项目取出一次锁?
谢谢
private List<string> _data = new List<string>(){"1","2","3","4","5"};
private object _locker =new object();
public IEnumerable<string> GetData()
{
lock (_locker)
{
foreach (string s in _data)
{
yield return s;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
2022 年 10 月更新
时隔多年再读这个答案,感觉原来的语气太刺耳了,给人一种混蛋的感觉。所以我稍微软化了语气。
抱歉让这个死而复生,但是阅读了丹尼尔接受的答案,然后自己测试一下,我认为至少应该告知那些最初投票的 10 个人错误答案。丹尼尔后来回顾了这一点,并将他的答案更新到此处。
正确答案是:在每次
yeald返回
之间永远不会释放锁。只有当枚举器完成时,即当
foreach
循环结束时,它才会被释放。丹尼尔左转的地方是错误地搭建了测试脚手架。他的代码不是多线程的,并且总是以相同的方式进行计算。该代码中的锁仅获取一次,并且由于它是同一个线程,因此它始终是相同的锁。
我从 @Daniel 的答案中获取了代码,并将其更改为使用 2 个线程,一个用于 List1,另一个线程为 List2 的每次迭代创建。
注意:这不是此代码的结构方式,为了使代码更清晰、更易于阅读,请参阅@EZI 提供的社区 wiki。
然而,这确实提供了与丹尼尔的代码的直接比较,并且它充实了原始代码的问题。
正如您所看到的,一旦
t2
线程启动,线程就会死锁,因为t2
正在等待一个永远不会被释放的锁。代码:
UPDATE 2022-Oct
Reading this answer after all these years, I felt the original tone was too harsh, and I came off as an a-hole. So I soften the tone a bit.
Sorry to resurrect this from the dead, but reading the accepted answer by Daniel, and then testing it myself I though that at least those original 10 people who up-voted should be informed of the incorrect answer. Daniel has reviewed this afterwards and updated his answer to point here.
The correct answer is: The lock is NEVER released between each
yeald return
.It will only be released when the enumerator is done, i.e. when the
foreach
loop ends.Where Daniel's made a left turn was by scaffolding the test incorrectly. His code is not multi-threaded, and it would always compute the same way. The lock in that code is taken only once, and since it's the same thread, it's always the same lock.
I took @Daniel's code from his answer, and changed it to work with 2 threads, one for List1 and another thread created for each iteration of List2.
NOTE: This is NOT how this code should be structured, for cleaner, easier to read code, see the community wiki provided by @EZI.
However, this does provide a direct comparison to Daniel's code and it fleshes out the issue with the original code.
As you can see once
t2
thread is started, the threads would dead-lock, sincet2
is waiting on a lock that would never be released.The Code:
@Lockszmith 有一个很好的收获(+1)。我只是发布这个,因为我发现他的代码很难阅读。这是一个“社区维基”。随时更新。
@Lockszmith has a good catch (+1). I only post this since I find his code hard to read. This is a "community wiki". Feel free to update.