6

async/await gained a lot of popularity in the C# world the past few years. Async functions also tend to spread rapidly within an application: Awaitables need to be awaited, therefore the calling function must be async and is therefore also an awaitable which needs to be awaited,... and so forth.

I'm using a C# library in a C++/Cli project. The library exposes async APIs. The Visual C++ compiler does not support async/await. Hence I have no way to await any of the APIs the library gives me.

I have the following options:

  • Call the async function and "letting it go": Not an option since I often need the return values to proceed.
  • Calling Wait() or accessing the Result property of the Task/Task<T> objects the async function returns: Causes the infamous dead-lock of the UI thread.

Is there any way to make this work? I wouldn't mind executing the async APIs synchronously if I have to.

Community
  • 1
  • 1
koloman
  • 711
  • 7
  • 19
  • 1
    Considering _"[This is a feature of the compiler. There were no CLR changes required to support async and await](http://stackoverflow.com/a/18494909/585968)"_; I wonder if you can do your own equivalent to the compiler encapsulation around `IAsyncResult` from c++/CLI point of view? –  Feb 16 '17 at 13:22
  • 2
    Have you try to use `Windows::Foundation::IAsyncOperation` ? – Tinwor Feb 16 '17 at 13:23
  • 3
    Cold hard fact is that you cannot wait and have to deal with the async nature of the method call. Anything you'd do to try to make it synchronous will either deadlock or hang the UI. Same coding pattern you needed to deal with any BeginXxx() call and what everybody wrote before .NET 4.5 – Hans Passant Feb 16 '17 at 13:31
  • 1
    One option with C++/CLI is to use `Task.ContinueWith`. Another one is to use `Task.GetAwaiter().OnCompleted`, this would be somewhat close to what C# compiler does. – noseratio Feb 16 '17 at 16:20
  • Thanks for all the hints. I will check it out tomorrow. @Dan I'm working on an old project with tons of C++ legacy code. I actually *do* use C++/Cli only for interop where I need it. – koloman Feb 16 '17 at 19:41
  • 2
    @Dan: Sure that would be great. But its not that simple. We are talking about a multi-million LoC legacy MFC desktop application. I will not go into details here but at some point I would *have* to call async functions from within existing C++ business logic. – koloman Feb 17 '17 at 07:05

1 Answers1

1

To me, it sounds like your problem is more of a symptom of a bigger issue. I personally try to avoid as much as I can putting business logic in a C++-CLI module. Specifically, I try to limit a ref class functionality to 3 main areas:

  • Translating managed method calls to native method calls (that includes transforming parameters if necessary).
  • Translating native return values to managed return values. This can even be translating an asynchronous function receiving a callback to a method returning Task.
  • Translating native events (callbacks) to managed events.

I Might be wrong, but in your situation it sounds like your C++ code is not well decoupled and you end up wiring different parts of it inside a C++-CLI module.

As for your question, I would use Task.ContinueWith family of methods to perform the asynchronous continuation instead of async / await. Yet, If you want the continuation to be invoked on a specific SynchronizationContext (such as UI thread) then special care must be taken to supply the right TaskScheduler.

Yennefer
  • 5,704
  • 7
  • 31
  • 44
Elad Maimoni
  • 3,703
  • 3
  • 20
  • 37
  • 1
    Right, "split the function and pass the part after `await` to `ContinueWith`" is exactly the magic the C# compiler does for `async` methods. Of course, "split the function" is non-trivial when you have local variables whose lifetime has to cross the split. – Ben Voigt Jul 28 '19 at 01:32
  • 1
    @Nina Kaprez You are exactly right. I was working on a legacy desktop application (C++/MFC). We tried to utilize internal C# libraries in the application and they exposed awaitable APIs. We ended up not using those APIs. – koloman Jul 29 '19 at 11:52