1

The question was already answered in the comments. Thanks.


tl;dr version: I'm trying to make an async run synchronously according to this , but it's freezing.

I have

BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);

Which works fine.

I need to change it to not being async, so I tried changing it to what was mentioned in this answer with:

BitmapDecoder decoder = SyncDecoder(BitmapDecoder.CreateAsync(stream));

where:

BitmapDecoder SyncDecoder(IAsyncOperation<BitmapDecoder> async) { return Task.Run(() => async.AsTask()).Result; }

or a longer (I think equivalent) version:

BitmapDecoder SyncDecoder(IAsyncOperation<BitmapDecoder> async)
{
    Func<Task<BitmapDecoder>> asLambda = () => async.AsTask();
    Task<BitmapDecoder> asTask = Task.Run(asLambda);
    asTask.Wait(); // freezes            
    return asTask.Result;
}

However, SyncDecoder never returns. (In the 2nd version it freezes on Wait().)

I tried making the same method for IReadOnlyList<StorageFile> (and storageFolder.GetFilesAsync()) and it does work fine. So it should work here too. But doesn't.

I know the UI thread should generally not be blocked but we need to fix existing code. Not undertake a large refactoring project. So how do I transform the code to be synchronous?

Community
  • 1
  • 1
ispiro
  • 26,556
  • 38
  • 136
  • 291
  • In the answer you linked to, the method that *starts* the async operation is wrapped inside of the `Task.Run()` call. In your example, you've already *called* `CreateAsync` and are just passing the *result* of that call, eventually, into a `Task.Run()`. – Damien_The_Unbeliever Jul 01 '16 at 13:20
  • @Damien_The_Unbeliever I tried it like this: `public static BitmapDecoder SyncDecoder(IAsyncOperation async) { return Task.Run(() => async.AsTask()).Result; } ` which is exactly like in the link. and it freezes as well. Besides, it shouldn't freeze. It should just go through the `Wait()` quickly. – ispiro Jul 01 '16 at 13:28
  • No, it's **not** exactly like the link. In the link, the operation that *starts* the asynchronous operation is called `asyncMethod`. In your example, the *equivalent* method is called `CreateAsync`. If you're not placing *that* method call within the `Task.Run()`, they are not in any way equivalent. `AsTask` takes an asynchronous operation that is *already in progress* and just changes the representation of that ongoing operation. – Damien_The_Unbeliever Jul 01 '16 at 13:34
  • @Damien_The_Unbeliever So be it. So why does the short version fail - see my edit - I tried it as you said. (I actually tried that first, but changed it in order to try to find what was going wrong.) – ispiro Jul 01 '16 at 13:37
  • *None* of the versions of the code in your question or the comments have `CreateAsync` being called from *inside* the `Task.Run()`. – Damien_The_Unbeliever Jul 01 '16 at 13:39
  • @Damien_The_Unbeliever Thank you for you persistence. I finally understood what you meant, and yes, that solved the problem! Thank you very much! You can transform your comment into an answer. (Now I'm trying to create a method for every place I have that. Like I tried to do here. But that's the next step...) – ispiro Jul 01 '16 at 13:45
  • 1
    It is not clear at all what you are asking, even if you do think you got an answer already. You say that you want to run the operation **synchronously**. But then you say you already know you're not supposed to block the UI thread (implying that you don't want to). Do you know what the word **synchronous** means here? It means that you _necessarily_ must block the thread in which you make the call. The only way to avoid blocking the UI thread is to execute the operation asynchronously _somehow_, or to change the context of the question so that _none_ of the code involved is executing in the UI – Peter Duniho Jul 01 '16 at 15:51
  • @PeterDuniho I want to block the UI. Not blocking has created much trouble, which I tried solving with the help of StackOverflow, but just got downvoted. The point is - I need this to block. (I just meant that I know that in _general_ blocking should be avoided. In this case - I want to block.) – ispiro Jul 01 '16 at 15:58
  • 2
    Blocking the UI thread causes deadlock. If you want to block the UI thread, then you also want to cause deadlock. Your code deadlocks. So, what's the problem? It seems to me the code is doing exactly what you want it to do. Fact is, while you say _"Not blocking has created much trouble"_, in reality running things asynchronously causes a lot _less_ trouble in the long run than deadlocking your UI thread. The answer here is not to deadlock the UI thread, but rather to learn how to correctly deal with asynchronous code so that it _doesn't_ "create much trouble". – Peter Duniho Jul 01 '16 at 16:48

1 Answers1

0

I know this question is quite old but I just stumbled across the same problem and here is my solution.

Freezing code

var t1 = BitmapDecoder.CreateAsync(randomStream).AsTask();
t1.Wait();
var decoder = t1.Result;

Non-freezing code

BitmapDecoder decoder;
var t1 = Task.Run(async () => decoder = await BitmapDecoder.CreateAsync(randomStream));
t1.Wait();

In this version the decoder creation runs on another thread and therefore doesn't block the ui and does not cause a deadlock.

Karim El Jed
  • 133
  • 6
  • `t1.Wait()` will still run on the UI thread, no? – Lasse V. Karlsen Aug 18 '22 at 09:35
  • I am not sure what the question behind your question is, but I think the important point is that the next line after the t1.Wait(); (not visible in the second version) will be executed on the UI thread after the BitmapDecoder has finished its work on the other thread. So the UI thread waits until it can execute this line, but it is not blocked. It is free to do some other stuff while it is waiting. – Karim El Jed Nov 11 '22 at 08:28