Continuations in C#, as exposed via the yield keyword and “iterator blocks”, is a seriously underused and under-researched feature. In C++, you can use Win32 fibers to accomplish the same, and this is in fact how they are implemented in the .NET 2.0 runtime. Update: They are not implemented using Fibers. Thanks for the clarification James. Learn something knew every day!

Did you know that you can use these to implement blocks of code that can literally jump between threads? Quite useful for UI code so you can avoid using all sorts of tedious synchronization and messaging primitives, and also avoid having to split your tasks into multiple functions. Instead of writing function 1 which kicks off a task on the thread pool, then function 2 that performs the long-running task (load a file, download some data, compute something useful), and then function 3 that executes on the UI thread when that is done and sets some UI flags … you can write 1 function that is hosted by a dispatcher or executor of some sort, and then use “yield return” to spit instructions at it. Need to report progress? No problem. Switch to the UI thread, tell your ProgressBar control what’s up, then switch back to the background thread. “yield return new SwitchTo(Thread.UI)” and “yield return new SwitchTo(Thread.Background)” are going to prove quite handy for Paint.NET v4.0.

I’ve been experimenting with this concept a little bit, and the results are promising. I have a simple application that has a “AsyncImageBox” control that uses continuations. It has one function, “LoadTheImage” which implements all of the logic for establishing a connection with a server, downloading the image, reporting progress in the UI, and hooking up the final image to the UI. When the block of code needs to do something that must be done on the UI thread (report progress), it just switches over to the UI thread and does it. Then it reverts to the background thread. This is all inside of 1 function of code, there is no “queue this to the thread pool” or “invoke this message over to the other thread” or “wait on this mutex” or “set this signal” nonsense. I can use traditional synchronous/blocking code (aka, “easier to write, read, debug, maintain, understand, etc.”) for all of this.

About these ads