2015-10-16 27 views
4

我懷疑下面的「庫」方法是否會實際工作,或者最終會死鎖。在異步方法中使用鎖

我整個有一個「老」對象需要被保護,「鎖定」似乎是最好的工具,因爲有一些重入調用該資源(SomeSharedResource)「類」。

編輯:

1)將調用「計算」​​實際上阻止或最壞情況僵局?

var finalResult = await Compute(3).ConfigureAwait(false); // will this block? 

2.)如果有人這樣做了?

var finalResult = Compute(3).Result; // will this block/deadlock? 

3.)2線程調用同時:

var finalResult = await Compute(3).ConfigureAwait(false); // will this block? 

在問題的方法:

private readonly object lockObject = new object(); 
private async Task<double> Compute(int input) 
{ 
    double result; 
    lock (lockObject) { 
     result = SomeSharedResource(input); 
    } 

    return await ComputeAsync(result).ConfigureAwait(false); // some other awaitable method 

} 
+0

只有當你有兩個鎖時纔會發生死鎖。當第一個鎖被鎖定在第二個對象上並且第二個鎖被鎖定在第一個對象時。這裏沒有辦法導致死鎖。 (糾正我,如果我錯了) –

回答

2
  1. Compute(int input)一個呼叫可肯定阻塞。您以同步的方式登錄到lock (lockobject)。如果一個線程持有lockObject,另一個線程嘗試獲取它,則第二個線程將在等待第一個線程完成時阻塞。

  2. 由於與#1相同的原因,這可能會阻止。它不會基於我們在這裏看到的死鎖,因爲結果延續不會繼承同步上下文。它也將阻塞的ComputeAsync()結果同步等待,因爲它使用.Result

  3. 這可以阻止同樣的理由#1。

鎖和延續是不同的概念。雖然我不能向你保證你的程序不會死鎖,但是因爲我看不到你的整個程序。你在這裏展示的任何東西都是乞求僵局(當然,除了典型的注意事項:.Result)。

但認識到鎖()的存在實際上是廣告阻止執行線程的可能性。關鍵字在某些同步執行的代碼中不會做任何奇怪的鎖定。

1

對於問題1,2和3的答案是,「他們可能不會死鎖」。儘管多個同時調用lock部分將會阻塞,因爲它們不能同時執行,但這並不意味着它們將會死鎖

您需要檢查lock內部發生的情況以確定該情況。

的危險是,如果lock內部的功能派生該結束調用回Compute()或其它代碼,還鎖定lockObject阻塞異步調用(await或等同物)。

只要lock內部的功能都沒有阻塞另一個線程,就應該是安全的。如果阻止異步調用,則需要驗證它們是否不重新輸入,或者確保不要阻止它們。

這裏是做什麼的一些例子,也不要因爲:

private async Task<double> DoSomething() 
{ 
    return await Compute(0); 
} 

private readonly object lockObject = new object(); 
private async Task<double> Compute(int input) 
{ 
    double result; 
    lock (lockObject) { 
     //This would be bad. 
     result = await DoSomething(); 

     //So would this. If you didn't wait inside the lock you wouldn't deadlock though. 
     var t = DoSomething(); 
     result = t.Result; 

     //This would be okay because it doesn't call back to Compute() 
     using (var stream = File.OpenText("test.txt")) 
     { 
      var contents = await stream.ReadToEndAsync(); 
     } 
    } 

    return await ComputeAsync(result).ConfigureAwait(false); // some other awaitable method 

} 
+1

鑰匙帶走是限制'鎖'下的代碼。 – bigtlb

2

這些問題都沒有實際的答案。他們的答案都是「是的,只要有足夠的操作條件,它們就會陷入僵局」。

如果你的意思是「將lock聲明導致阻塞或死鎖?」,那麼答案是肯定的阻塞和不爲死鎖(假設SomeSharedResource(input)是乖巧的,即沒有內部死鎖)。