在Windows存储异步文件方法期间避免死锁的正确方法是什么

时间:2015-10-01 06:40:43

标签: c# async-await

我正在尝试编写一个函数来从Windows 8商店应用程序的漫游文件夹中加载一些数据。

我在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;
    }

1 个答案:

答案 0 :(得分: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);
}