3 ms·
> All .NET async APIs take an optional cancellation token parameter [...] The best part about this is that it pervades the entire .NET runtime, the APIs, code e
by nwallin 7y ago
> All .NET async APIs take an optional cancellation token parameter [...] The best part about this is that it pervades the entire .NET runtime, the APIs, code examples, and has excellent documentation on correct usage patterns.
This statement is completely false. The .NET runtime is inundated with bad code examples resulting in deadlocks with async code.
In my professional experience, the WriteableBitmap class is completely unusable. All official code samples exhibit the same brokenness.
They all tell you to do the same thing: lock() on the WriteableBitmap object, get the buffer, perform an update the buffer, unlock() on the WriteableBitmap object. But you try to lock() on a backgroundworker (the sane thing to do) and it fails because lock() can only be called from the UI thread. So you lock() on the UI thread, async into a backgroundworker (the second most sane thing to do) to update the buffer, and boom, WPF deadlocks. The official Microsoft UI framework uses .Lock(), not .TryLock(), and you are deadlocked forever. There is no solution to this problem. No solution exists. Abandon all hope ye who enter here.
C#/.NET+async is horrible. Maybe this is the best async implementation that's been done, but if that's the case, the best implementation is worse than starting a new thread every time you need to block on IO. The only way to write good async C#/.NET code is to not write async C#/.NET code. But guess what? As you said, C#/.NET is inundated with async APIs, and it falls down every time you blink at it.
C++ is looking to standardize async/await into the language. I think I'd rather pick up growing corn.
https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.imaging.writeablebitmap https://docs.microsoft.com/en-us/dotnet/api/system.windows.m...
- BoiledCabbage 7y agoHow are you "asyncing" to the "backgroundworker" thread? Await? Task.run? Are you using a .Return? I can't see your code, but this sounds more like a misunderstanding of the requirements around a UI thread and the task scheduler than any issue with async. https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d https://medium.com/rubrikkgroup/understanding-async-avoiding... And the below seems to be a correct implementation of your desired functionality. https://stackoverflow.com/questions/9868929/how-to-edit-a-writablebitmap-backbuffer-in-non-ui-thread https://stackoverflow.com/questions/9868929/how-to-edit-a-wr...
- nighthawk648 7y agoYes, I don’t understand why original commenter is so angry about c#/.net. Maybe a bad experience? Async .net may have some pitfalls but it is overall versatile which was the original sentiment anyways...
- nwallin 7y agoFirst of all, your original post claimed that the official documentation is good. I posted an example of where the official docs are dumb and wrong. You posted a random blog article and a stack overflow answer as a rebuttal. Just so we're clear, you agree that the official documentation is dumb, wrong, and incomplete? Second, the "seems to be correct" article you linked is what we did. It's a sensible, logical solution to the problem. Which is why we wrote it that way to begin with. Hell, we might have copied it directly from that SO answer. It doesn't work. It deadlocks. You call out to the UI thread dispatcher, lock the object, then go back to doing stuff on a background thread. Some time later, the UI thread is updating the UI, and it tries to update your element, and it tries to lock on the lock object. (it can't, because it's already locked) Some time later, the background task is done. It schedules a task on the UI thread to unlock the object. There's a problem though: the UI thread is locked on a mutex. A single hardware thread cannot wait on both a mutex and the task queue at the same time. Deadlock. Just because it's the highest voted answer on SO doesn't mean that it isn't completely wrong. The second highest voted answer states that what the questioner is asking for is impossible. This answer is the correct one. Our least bad solution to this problem is to update a buffer owned by the background thread, and then use the UI thread to copy pixels from the background thread's buffer to the UI thread's buffer. Lock, copy the buffer, unlock, without ever relinquishing control of the UI thread. This solution is not ideal from a performance standpoint, but at least it doesn't deadlock. C#/.NET's async is fine if you're not doing anything more complicated than querying a database or paying data around on a socket. It falls down really hard if you start tickling its underbelly.
- Const-me 7y ago> But you try to lock() on a backgroundworker (the sane thing to do) That’s just a leaky abstraction. Updating image from background thread is a sane thing to do from general-purpose programmer POV. To understand why it’s not so good idea, and why it’s not supported, you need to know what happens under the hood. Specifically, how 3D GPU hardware works and executes these commands. > No solution exists. From graphic programmers POV, the sane solution — only call GPU from a single thread. In D3D11 there’re things which can be called from background threads. It’s possible to create new texture on the background thread uploading the new data to VRAM, pass the texture to the GUI thread, then on the GUI thread either copy between textures (very fast) or replace textures destroying the old one (even faster). Unfortunately, doing so is slower in many practical use cases, like updating that bitmap at 60Hz: creating new resources is relatively expensive, more so than updating preexisting one.