2011-01-05 59 views
29

我有以下方法:C#收益率是否解鎖?

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),試圖擺脫一些concurancy問題。我很好奇,yield return會釋放Database上的鎖定,然後在下一次迭代時重新鎖定?或者Database在整個迭代期間保持鎖定狀態?

+1

請參閱http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx – 2011-01-05 19:18:22

+6

這是一個潛在的*非常糟糕的主意*。當您可以在獲取鎖定和釋放鎖定之間運行任意代碼時,很難控制鎖定順序。這只是要求解決死鎖問題。 – 2011-01-05 21:23:07

+0

@Eric Lippert - 我不太熟悉多線程編碼。 (雖然我現在越來越好了。)現在我知道鎖定語句的「魔力」實際上只是一個「最終嘗試」塊,並且「yield」在處於收縮狀態時保持範圍。考慮到這一點,將鎖移動到只包圍'for'循環。這給我對SQL Server CE訪問的限制,我需要在「關閉」迭代期間不鎖定的情況。 (至少我希望如此!) – Vaccano 2011-01-05 21:27:24

回答

19

yield return不會導致任何鎖被釋放/解鎖。 lock語句將擴展爲try/finally塊,迭代器將不會以與迭代器方法中明確的try/finally不同的方式對待它。

的細節是一個比較複雜,但用於當finally塊將一個迭代方法內運行的基本規則是

  1. 當迭代器被暫停,並且Dispose在點被稱爲在範圍finally塊的暫停將運行
  2. 當迭代器正在運行並且代碼會以其他方式觸發finallyfinally塊運行。
  3. 當迭代器遇到yield break陳述的範圍內的finally塊在yield break點將運行
+0

@Marc更明確地表示,它的處理方式與迭代器方法中定義的任何其他try/finally方法無異。 – JaredPar 2011-01-05 19:19:58

+0

您是否編輯過?我相信這一點不太清楚:) – 2011-01-05 19:20:18

+0

@Marc耶編輯,使我的意圖更清晰後,我讀你的評論。 – JaredPar 2011-01-05 19:22:37

5

數據庫對象將被鎖定,直到迭代完成(或迭代器設置)。

這可能會導致過度鎖定,我建議不要這樣做。

+2

+1上存在鎖定,並且我同意過度的鎖定期限,那麼對於您的應用程序是否可以確定是困難/不可能確定的。 – 2011-01-05 19:17:20

2

該鎖持續有效,直到您超出鎖定範圍()。屈服不會那樣做。

13

鎖轉換爲嘗試/最後(正常C#)

在迭代器塊(又名產率), 「最後」 成爲IDisposable.Dispose()執行枚舉的一部分。當您使用最後一個數據時,也會在內部調用此代碼。 「foreach」會自動調用Dispose(),所以如果你使用「foreach」(或者regualar LINQ等),會將解鎖。

但是,如果呼叫者使用的GetEnumerator()直接(很少見)和犯規讀取所有數據和調用Dispose(),那麼鎖將不會被釋放。

我將不得不檢查是否或得到一個finaliser;它可能獲得GC發佈,但我不會賭錢。