@cheong: No, that's going to have several problems, including those he's already pointed out. You shouldn't mix async with blocking APIs.
12 hours ago, BitFlipper wrote
The thing is that there is no deterministic behavior, so one would be guessing and hoping that whatever you call into happens synchronously.
You are absolutely right that there's no deterministic behavior here, but I don't fully agree with the rest of your conclusion. Again, I wouldn't jump to any conclusions until I'd profiled.
Yea that is why I'm having problems. Everything is based on this flawed idea that only the UI can possibly initiate calls into these APIs, and hence the overzealous asyncing of all APIs. The code I'm writing has nothing to do with the UI and these are dedicated background threads. Forcing this async pattern from top to bottom is causing other patterns to break.
I think you missed the point here. Being on the UI thread increases the danger, but being on a background thread doesn't make it safe to switch in and out of async. With very careful attention to what you're doing, you can actually do this. But it's complicated enough that I'd just warn against doing this. It's far easier and safer to just remain "async all the way", as they say.
I wasn't trying to alleviate the overhead, I was trying to make the code thread safe by not breaking locks that are held earlier in the stack. I'm painfully aware of the latencies that are added even when using Wait. Since the API I need to use has only an async version available, I'm forced down this path. It once again comes down to trying to force the UI threading model into everything else.
It's not really an issue of "breaking locks". If that's all it were, there'd be ways to ensure the locks aren't broken. No, the issue is that locks were never intended to be used that way (i.e. held for an indeterminate amount of time while an asynchronous operation is being performed). It's just not safe to do that. Even holding a lock for longer periods of time can sometimes be problematic, so holding the lock even while doing synchronous I/O isn't necessarily the best way to architect this.
As I mentioned I can probably move the file IO code out of the audio processing threads but I wonder what will happen when async ends up being the only choice (it seems we are moving in that direction).
BTW I like your idea of providing sync and async versions of all APIs but have the sync versions throw exceptions if they are called from a UI thread. We already have these types of invalid cross-thread checks when you make calls into controls. And the sync versions should not be thin wrappers around the async versions, like this:
Yeah, like I said, I get why Microsoft did this. Currently, WinRT is mostly just a UI framework, and their discouraging (actually, preventing) all of the bad habits developers have had for decades in that domain. However, just because I get that, doesn't mean I fully agree with the decision. Yes, make async pervasive, but don't make it the only choice, as there are times where async is not a good choice. So, don't confuse my attempts to find solutions for you as an endorsement of the current state. :)