GetFileAsync() を await する呼び出しが返されず、WinRT アプリでアプリがハングする 質問する

GetFileAsync() を await する呼び出しが返されず、WinRT アプリでアプリがハングする 質問する

アプリケーションの起動時に設定ファイルを読み込んで読み込もうとしていますが、約 90% の確率で設定ファイルawait GetFileAsync("filename.xml");が返されず、アプリケーションがハングします。

約 4 分の 1 の確率で、コードをステップ実行すると、実際に戻ってファイルを読み取ります。

以下に、非常に簡略化されたバージョンのコードを示します。

App.xaml.cs:

protected override void OnLaunched(LaunchActivatedEventArgs args)
{
    FileLoader.Load().Wait();

    // File-load dependent stuff
}

ファイルローダー.cs:

public async static Task Load()
{
    StorageFolder folder = ApplicationData.Current.LocalFolder;
    StorageFile file;
    bool fileExists = true;

    try
    {
        // The following line (often) never returns
        file = await folder.GetFileAsync("filename.xml");
    {
    catch
    {
        fileExists = false;
    }

    // Do stuff with loaded file
}

Visual Studioの出力ウィンドウを見ると、しばらく待つと"The thread '<No Name>' (0x30c) has exited with code 0 (0x0)."

ここで何が起こっているのか誰か分かりますか?

ベストアンサー1

デフォルトでは、まだ完了していない操作を実行するとawaitTaskメソッドはキャプチャされたコンテキスト (この場合は UI コンテキスト) で再開されます。

コードが失敗する理由は次のとおりです。

  • OnLaunched呼び出しLoad(UI コンテキスト内)。
  • Load待機します。これにより、Loadメソッドは未完了のタスクを返し、後で完了するようにスケジュールします。この継続は UI コンテキストに対してスケジュールされます。
  • OnLaunchedから返されたタスクをブロックしますLoad。これにより、UI スレッドがブロックされます。
  • GetFileAsync最終的に完了し、 の継続を実行しようとしますLoad
  • 継続は、LoadUI スレッドが使用可能になるまで待機し、UI コンテキストで実行できるようになります。
  • この時点で、 は完了をOnLaunched待機しておりLoad(これにより UI スレッドがブロックされます)、LoadUI スレッドが解放されるのを待機しています。デッドロックです。

次のベスト プラクティスにより、このような状況を回避できます。

  1. 「ライブラリ」asyncメソッドでは、ConfigureAwait(false)可能な限り を使用します。あなたの場合、これはawait folder.GetFileAsync("filename.xml");に変更されますawait folder.GetFileAsync("filename.xml").ConfigureAwait(false);
  2. sでブロックしないでください。s はずっと下にTaskあります。つまり、に置き換えます。asyncWaitawait

詳細については:

更新、2012-07-13:この回答を組み込んだブログ記事に

おすすめ記事