0

Hello fellow programmers, i'm beginner to async programming I confess. Today I have ran some tests with async operations and found something rather interesting: When I call await myStorageFolder.GetFilesAsync(); My async function gets frozen and doesn't throw any exception, but the task never completes, although, if I call myStorageFolder.GetFilesAsync().AsTask().Result; instead, the command returns the data as expected, almost instantly (just as fast as winforms Directory.GetFiles())

Now, my problem here is, writing these lines:

var myFileStream = await myFile.OpenAsync(Windows.Storage.FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(myFileStream);

In this case the await works very well on OpenAsync, but not in the BitmapDecoder.CreateAsync (which freezes), and, casting it to a Task and calling its "Result" property doesn't make it any faster.

So this is my question, what is the best approach to get around with this async programming and, whats the difference between calling (await) and (AsTask().Result), if, theoretically both will run "synchronously" in the async thread?

EDIT: Here is my function: Edit2: Translated my variable names to english

private async Task ExecuteComparatorAsync(StorageFolder folder)
{
    _cancel = false;
    Progress = 0;
    Status = "Image comparator started.";
    List<ImageData> ImagesToCheck = new List<ImageData>();
    Status = "Searching Images...";
    // if I use await on the next line, the whole function becomes irresponsive and will never return
    IReadOnlyList<StorageFile> Files = folder.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.DefaultQuery).AsTask().Result;
    Status = "Let me see these images...";
    foreach(StorageFile f in Files)
    {
        try
        {
            ImageData iData = await GetImageData(f);
            ImagesToCheck.Add(iData);
        }
        catch (Exception s) {
            String j = s.Message;
        }
    }
    Status = "Got it.";
    List<String> RepetedPaths = new List<String>();
    for (int i = 0; i < ImagesToCheck.Count; i++)
    {
        Status = "Comparing images " + i + "/" + ImagesToCheck.Count;
        for (int j = 0; j < ImagesToCheck.Count; j++)
        {
            if (_cancel)
                return;
            Boolean IsImageIRepeated = false;
            Double Difference = await Compare(ImagesToCheck[i], ImagesToCheck[j]);
            if (Difference < MinDiff)
            {
                String repeatedImage = String.Empty;
                if (ImagesToCheck[i].Size > ImagesToCheck[j].Size)
                {
                    repeatedImage = ImagesToCheck[j].Path.Path;
                    Debug.WriteLine("Duplicate: {0}", ImagesToCheck[j].Path.Path);
                }
                else
                {
                    IsImageIRepeated = true;
                    repeatedImage = ImagesToCheck[i].Path.Path;
                    Debug.WriteLine("Duplicate: {0}", ImagesToCheck[j].Path.Path);
                }
                RepeatedPaths.Add(repeatedImage);
            }
            if (IsImageIRepeated)
                break;
        }
        Progress = (i * 100) / ImagesToCheck.Count;
    }
    Status = String.Format("Done. {0} repeated images found.", Repetidas.Count);
    Finished = true;
}

Here is my major problem:

async static Task<WriteableBitmap> LoadImage(StorageFile myFile, UInt32 Width, UInt32 Height)
    {
        var fStream = await myFile.OpenAsync(Windows.Storage.FileAccessMode.Read);
        try 
        { 
            // The next line interrupts my entire operation.
            BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fStream);
            // AsTask().Result doesn't work either;
            // No exceptions are thrown here.

            InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream();
            BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(ras, decoder);

            enc.BitmapTransform.ScaledHeight = Height;
            enc.BitmapTransform.ScaledWidth = Width;

            BitmapBounds bounds = new BitmapBounds();
            bounds.Height = Height;
            bounds.Width = Width;
            bounds.X = 0;
            bounds.Y = 0;
            enc.BitmapTransform.Bounds = bounds;
            try
            {
                await enc.FlushAsync();
            }
            catch (Exception ex)
            {
                string s = ex.ToString();
            }
            WriteableBitmap bImg = new WriteableBitmap((int)Width, (int)Height);
            await bImg.SetSourceAsync(ras);
            return bImg;
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.Message);
            throw new Exception("This file is maybe, not an image at all...");
        }
    }
Felype
  • 3,087
  • 2
  • 25
  • 36
  • Await will **not** run synchronously in the calling thread of your async function... – Adriano Repetti Aug 25 '14 at 21:00
  • 1
    What do you mean by freezes? Is your application unresponsive? or simply the method halts until its done? – Yuval Itzchakov Aug 25 '14 at 21:01
  • I mean, if I place "foo = await something()", and surround with breakpoints, the following line won't be reached until the "await" something returns, so, it sounds to me like it ends up running pseudo-synchronously, like one thread waiting for the other to return a value. – Felype Aug 25 '14 at 21:02
  • @YuvalItzchakov Yes, the next line wont run, no exceptions are thrown. The async method does never return or completes. – Felype Aug 25 '14 at 21:03
  • No tats the point of `await`, when you do `.Result` or `await` they both "stop" on that line of code, however the difference is `.Result` blocks the thread waiting where `await` frees the thread to do other work. The problem is when `await` tries to come back after the thread was freed and tries to get it back when the work is finished and you locked up the thread waiting for something else you can end up in a deadlock. – Scott Chamberlain Aug 25 '14 at 21:03
  • 1
    This question is impossible to answer, you need to provide the code to your Async methods. Writing Async code is not as simple as preappending your methods with the Async keyword, you need to be *very* careful. – Erik Philips Aug 25 '14 at 21:04
  • [BitmapDecoder](http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapdecoder(v=vs.110).aspx) does not have a `CreateAsync()` method (I can find), you need to provide the code. – Erik Philips Aug 25 '14 at 21:05
  • 1
    How are you calling `ExecutarComparadorAsync` – Yuval Itzchakov Aug 25 '14 at 21:07
  • 1
    You should probably begin to read [Async and await](http://blog.stephencleary.com/2012/02/async-and-await.html). If you are going to post code, please post the *entire* signature. – Erik Philips Aug 25 '14 at 21:09
  • @Felype your problem is in the code that calls `ExecuteComparator` (aka `ExecutarComparadorAsync`, you did not need to translate it, we understood what you meant, in fact translating likely introduced more errors). Please show the code for the function that calls `ExecutarComparadorAsync` (and the call chain all the way up the stack as far as you can go would be useful) – Scott Chamberlain Aug 25 '14 at 21:15
  • 3
    [Don't Block on Async Code](http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html) – Craig Gidney Aug 25 '14 at 21:16
  • 1
    So the problem is not in `LoadImage`, you need to keep going up the chain till you find where you called `.Result` or `.Wait` somewhere. – Scott Chamberlain Aug 25 '14 at 21:22
  • 2
    `theoretically both will run "synchronously" in the async thread` Here's your misunderstanding. There is no "async thread". The entire point of `async` is to do things *without* involving blocked threads. I recommend reading [my `async` intro blog post](http://blog.stephencleary.com/2012/02/async-and-await.html) – Stephen Cleary Aug 25 '14 at 21:23
  • 1
    @StephenCleary I'd mark this as my answer. It is indeed that my problem: A consecutive task in my calling thread was blocking the async operation previously called. I really thought async was related to multithreading, since Task lies within System.Threading. Just a remark, i'm reading your article and it really makes much more sense than MSDN explanation on Async and Await, ty. – Felype Aug 25 '14 at 21:43

1 Answers1

2

Typical case of deadlock due to calling Result or Wait somewhere. Audit your entire code to remove calls to those deadlock-prone functions. Or, call them in a deadlock-safe way.

usr
  • 168,620
  • 35
  • 240
  • 369