2015-10-01 40 views
1

我正試圖編寫一個函數來從Windows 8商店應用程序的漫遊文件夾中加載一些數據。什麼是避免Windows庫存異步文件方法期間死鎖的正確方法

我在Load方法的roamingLoad.Wait()上遇到死鎖(掛起);

這樣做的正確方法是什麼?以下是什麼做錯了?

編輯:我應該指出,如果我在調試器中執行它,它可以很好地工作。

有沒有辦法做到這一點,沒有頂級方法成爲異步?如果我這樣做,那麼每個調用方法都必須等待阻止,直到完成否。

public override bool Load(string in_FileNameAndDirectory, StreamTask in_StreamTask, bool in_PreferRoaming) 
    { 
     if (PreferRoaming && SupportsRoamingSave) 
     { 
      try 
      { 
       Task<bool> roamingLoad = RoamingLoadAsync(in_FileNameAndDirectory, in_StreamTask); 
       roamingLoad.Wait(); 
       return roamingLoad.Result; 
      } 
      catch (Exception error) 
      { 
       return false; 
      } 
     } 
     return Load(in_FileNameAndDirectory, in_StreamTask); 
    } 


    private async Task<bool> RoamingLoadAsync(string inFileNameAndDirectory, StreamTask inStreamTask) 
    { 
     try 
     { 
      StorageFolder roamingFolder = ApplicationData.Current.RoamingFolder; 
      StorageFile sampleFile = await roamingFolder.GetFileAsync(inFileNameAndDirectory); 

      using (Stream stream = await sampleFile.OpenStreamForReadAsync()) 
       inStreamTask(stream); 
     } 
     catch (Exception error) 
     { 
      return false; 
     } 
     return true; 
    } 
+0

你的方法是同步的。你可以使'Load'方法異步,並返回任務。然後繼續執行其餘部分。 – nomail

+0

我試着測試你的代碼,但隨後VS2015編輯器再次陷入僵局,微軟也無法做到這一點。你的代碼會因爲你從未真正開始任務而死鎖。通過首先意識到任何使線程看起來容易的抽象增加了五個新的不可解決的問題,通過使用調試> Windows>任務調試器窗口來診斷停滯的任務,並通過嚴格遵循貨物崇拜的方法來應用充分的幫助,您可以避免這些相當不可避免的和難以糾正的錯誤編碼樣本。異步/等待是一直下降的龜,偏離模式購買痛苦。 –

+0

只是一個側面說明,真的有必要將OpenFreamAsync和inStreamTask分開GetFileAsync嗎?只需將它們包裝成一個任務以避免不必要的上下文切換 – cscmh99

回答

1

什麼是做這種正確的方法是什麼?

您正遇到common deadlock problem(我在博客中全面解釋)。總而言之,您不應該在異步任務上使用Task.WaitTask<T>.Result。相反,你應該使用await

爲了使用await,您的方法必須是async。這意味着,這個簽名是剛剛與異步操作根本不相容:

public override bool Load(string in_FileNameAndDirectory, StreamTask in_StreamTask, bool in_PreferRoaming) 

假設bool結果確實非常重要(這當然是值得商榷 - 返回bool結果,而不是例外是那種80年代,就不會你說的),寫這個正確辦法是改變的基類簽名以使其支持異步操作:

public override async Task<bool> LoadAsync(string in_FileNameAndDirectory, StreamTask in_StreamTask, bool in_PreferRoaming) 
{ 
    if (PreferRoaming && SupportsRoamingSave) 
    { 
    try 
    { 
     return await RoamingLoadAsync(in_FileNameAndDirectory, in_StreamTask); 
    } 
    catch (Exception error) 
    { 
     return false; 
    } 
    } 
    return Load(in_FileNameAndDirectory, in_StreamTask); 
} 
+0

這是不是意味着我將不得不在所有地方等待我稱爲此方法(loadasync)以阻止它完成?我真的只是希望這是一個標準的非異步方法調用(這個代碼在後臺線程上調用),我只是想調用它,讓它完全處理,並返回一個布爾值,如果它失敗或沒有。 –

+0

@DanielArmstrong:是的,你將不得不「等待」 - 這就是整個想法。你不能在異步方法上有一個同步方法塊,而不會進入黑客和痛苦的整個世界。 –

+0

要使用它必須是一個異步方法...這對我來說根本不起作用,xbox 360不支持異步,我們希望跨所有平臺使用相同的方法簽名。 如果我在調用LoadAsync時使用await並使調用函數異步,那麼我也不得不讓調用該方法的方法也等待,等等,直到我最頂級的方法調用? –

相關問題