C# Yield 是否会释放锁?
我有以下方法:
public static IEnumerable<Dictionary<string, object>> GetRowsIter
(this SqlCeResultSet resultSet)
{
// Make sure we don't multi thread the database.
lock (Database)
{
if (resultSet.HasRows)
{
resultSet.Read();
do
{
var resultList = new Dictionary<string, object>();
for (int i = 0; i < resultSet.FieldCount; i++)
{
var value = resultSet.GetValue(i);
resultList.Add(resultSet.GetName(i), value == DBNull.Value
? null : value);
}
yield return resultList;
} while (resultSet.Read());
}
yield break;
}
我刚刚添加了 lock(Database)
来尝试消除一些并发问题。不过我很好奇,yield return
会释放 Database
上的锁定,然后在下一次迭代时重新锁定吗?或者数据库
会在整个迭代期间保持锁定状态吗?
I have the following method:
public static IEnumerable<Dictionary<string, object>> GetRowsIter
(this SqlCeResultSet resultSet)
{
// Make sure we don't multi thread the database.
lock (Database)
{
if (resultSet.HasRows)
{
resultSet.Read();
do
{
var resultList = new Dictionary<string, object>();
for (int i = 0; i < resultSet.FieldCount; i++)
{
var value = resultSet.GetValue(i);
resultList.Add(resultSet.GetName(i), value == DBNull.Value
? null : value);
}
yield return resultList;
} while (resultSet.Read());
}
yield break;
}
I just added the lock(Database)
to try and get rid of some concurancy issues. I am curious though, will the yield return
free the lock on Database
and then re-lock when it goes for the next iteration? Or will Database
remain locked for the entire duration of the iteration?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
否,
yield return
不会导致任何锁被释放/解锁。lock
语句将扩展为try /finally
块,并且迭代器不会将其与显式try/finally
中的处理方式区别对待。迭代器方法。细节有点复杂,但是
finally
块何时在迭代器方法内运行的基本规则是Dispose
被调用时挂起点范围内的finally
块将finally
块运行。yieldbreak
语句时,finally
块将在yieldbreak
处运行No the
yield return
will not cause any locks to be freed / unlocked. Thelock
statement will expand out to atry / finally
block and the iterator will not treat this any differently than an explicittry / finally
in the iterator method.The details are a bit more complicated but the basic rules for when a
finally
block will run inside an iterator method isDispose
is called thefinally
blocks in scope at the point of the suspend will runfinally
thefinally
block runs.yield break
statement thefinally
blocks in scope at the point of theyield break
will run锁转换为 try/finally(普通 C#)。
在迭代器块(又名yield)中,“finally”成为枚举器的IDisposable.Dispose()实现的一部分。当您使用最后一个数据时,也会在内部调用此代码。
“foreach”自动调用 Dispose(),因此如果您使用“foreach”(或常规 LINQ 等),它将会被解锁。
但是,如果调用者直接使用 GetEnumerator()(非常罕见)并且不读取所有数据并且不调用 Dispose(),则锁不会被释放。
我必须检查它是否有最终确定者;它可能会被GC释放,但我不会在上面打赌。
The lock translates to try/finally (normal C#).
In Iterator blocks (aka yield), "finally" becomes part of the IDisposable.Dispose() implementation of the enumerator. This code is also invoked internally when you consume the last of the data.
"foreach" automatically calls Dispose(), so if you consume with "foreach" (or regular LINQ etc), it will get unlocked.
However, if the caller uses GetEnumerator() directly (very rare) and doesn't read all the data and doesn't call Dispose(), then the lock will not be released.
I would have to check to see if it gets a finaliser; it might get released by GC, but I wouldn't bet money on it.
数据库对象将被锁定,直到迭代完成(或迭代器被释放)。
这可能会导致锁定时间过长,我建议不要这样做。
The Database object will be locked until iteration finishes (or the iterator is disposed).
This might lead to excessive periods of locking, and I would recommend against doing it like this.
锁一直有效,直到超出 lock() 的范围。屈服并不能做到这一点。
The lock remains in effect until you get outside of the scope of lock(). Yielding does not do that.