简体   繁体   English

C#Yield是否可以免费锁定?

[英]Does the C# Yield free a lock?

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. 我刚刚添加了lock(Database)来尝试摆脱一些尴尬的问题。 I am curious though, will the yield return free the lock on Database and then re-lock when it goes for the next iteration? 我很好奇, yield return是否会释放Database上的锁定,然后在下一次迭代时重新锁定? Or will Database remain locked for the entire duration of the iteration? 或者Database会在整个迭代期间保持锁定状态吗?

No the yield return will not cause any locks to be freed / unlocked. yield return不会导致任何锁定被释放/解锁。 The lock statement will expand out to a try / finally block and the iterator will not treat this any differently than an explicit try / finally in the iterator method. lock语句将扩展为try / finally块,并且迭代器不会对迭代器方法中的显式try / finally进行任何不同的处理。

The details are a bit more complicated but the basic rules for when a finally block will run inside an iterator method is 细节有点复杂,但finally块在迭代器方法中运行的基本规则是

  1. When the iterator is suspended and Dispose is called the finally blocks in scope at the point of the suspend will run 当迭代器被挂起并且调用Dispose时,将在暂停点的范围内运行finally
  2. When the iterator is running and the code would otherwise trigger a finally the finally block runs. 当迭代器正在运行并且代码将以finally触发finally块时运行。
  3. When the iterator encounters a yield break statement the finally blocks in scope at the point of the yield break will run 当迭代器遇到yield break语句时, yield break run的点范围内的finally块将会运行

The lock translates to try/finally (normal c#) 锁转换为try / finally(正常c#)

In Iterator blocks (aka yield), "finally" becomes part of the IDisposable.Dispose() implementation of the enumerator . 在Iterator块(又名yield)中,“finally”成为枚举器的IDisposable.Dispose()实现的一部分。 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 regualar LINQ etc) it will get unlocked. “foreach”会自动调用Dispose(),所以如果你使用“foreach”(或regualar LINQ等), 它将被解锁。

However, if the caller uses GetEnumerator() directly (very rare) and doesnt read all the data and doesn't call Dispose() then the lock will not be released. 但是,如果调用者直接使用GetEnumerator()(非常罕见)并且读取所有数据并且调用Dispose(),则不会释放锁定。

I would have to check to see if or gets a finaliser; 我必须检查是否或获得终结者; it might get released by GC, but I wouldn't bet money on it. 可能会被GC释放,但我不会赌钱。

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. 这可能导致过多的锁定时间,我建议不要这样做。

The lock remains in effect until you get outside of the scope of lock(). 锁定保持有效,直到您超出lock()的范围。 Yielding does not do that. 让步不会那样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM