Paradigm Shift – Designing Asynchronous Programs Using the CCR
I recently had a chance to experiment with the Concurrency and Coordination Runtime — a foundational component of Microsoft Robotics Developer Studio. I’ve been really impressed so far — the CCR provides an excellent framework for writing and coordinating the asynchronous operations typically encountered in a multi-threaded application. It turns out that robotics is just one specific application and that the CCR is very general and applicable in many other (even enterprise-level) scenarios.
Getting into the CCR mind-set has been a really interesting experience for me. Because of the asynchronous nature, it forces you to step back from your problem and really investigate what is happening from a higher-level perspective. Synchronous and asynchronous programming are really two different worlds, and have to be approached as such. As I’ve been experimenting, writing CCR-compatible code at times has felt like I needed to rewire my brain
Hopefully this post can try and document some of these thought patterns and not only provide a source of CCR examples, but also illustrate the sheer power that this paradigm opens up.
This article, these two videos, and this blog post series are required reading for anyone wanting to jump into the CCR.
- Concurrent Affairs – Concurrency and Coordination Runtime article by Jeffrey Richter
- CCR Programming – Jeffrey Richter and George Chrysanthakopoulos
- Concurrency and Coordination Runtime with George Chrysanthakopoulos
- NickG at iodyne.blogspot.com and his 9-part series on the CCR: Part 1, Part 2, Part 3, Part 4, Part 5, Part 6, Part 7, Part 8, Part 9 *
Ok, let’s jump into a simple example.
While Loop
Let’s go all the way back to Programming 101 and investigate a typical while loop:
int counter = 0;
while (counter < 10)
{
counter++;
Console.WriteLine(counter);
}
Pretty simple. While a counter variable is less than 10, increment it and write the value to the console. Now let’s consider the hypothetical situation where we have more complex operations than comparing to 10 and writing to the console. What if these operations took a long period of time? For example, fetching a file from a URL, loading a large file from disk, etc. It would be a complete waste of system resources to block a thread while we’re waiting for these operations to complete. Let’s try to do this asynchronously with the CCR.
Message Passing
In a nutshell, the CCR allows programmers to write their programs with a "message-passing" mentality. Instead of using the sequential mindset of "Do these 3 things in order, one after the other", you write code that says "Whenever a message arrives here, go and do this thing". Messages are passed around by "posting" them to a Port. A port is just a queue of (strongly-typed) messages. Multiple messages can be posted to the port (placed in the queue) at any given time. So, to accomplish our asynchronous while loop example, we need to take a step back and think about what’s really going on from a message-passing point of view.
Dissect the Operations
The first thing that we need to is determine all operations (snippets of code) that are going happening. We obviously have a loop body (in this case, just incrementing the counter and writing it to the console). There is another snippet of code lurking as well — the predicate that gets evaluated to test whether or not the loop should continue. So, we’ve identified two operations, the Loop Body and the Predicate:
Identify the Messages
Next we need to identify the messages that travel between the various operations. We note three things here:
- If the predicate evaluates to true, it can pass the counter to the loop body.
- The loop body always passes the counter back to the predicate for evaluation
- The program passes the initial counter value of 0 to the predicate
Let’s draw these messages onto our diagram:
Identify the Ports
Any communication between two operations must occur through a port, so this means that each arrow in the diagram must become a port. We also see a chance to simplify — there are two arrows with identical types (integer counters) pointing into the predicate operation, so we can combine them. This leaves us with two ports to place in the middle:
We decide to name the ports based on the operation that they point to. So, the port containing messages that the Loop Body will handle is called the loopPort, and the port containing messages that the Predicate operation will handle is called the predicatePort. We also note that the arrow pointing into the port is a Post operation, and the arrow pointing out of the port is a Receive operation.
Separate the Logic
The final step towards obtaining the CCR-compatible code for the asynchronous while loop involves separating out all of the receiver logic. We need to provide answers to the question "What happens to my message when I post it to a certain port?" Basically we are "wiring up" the logic of the application. This involves creating groups of all ports and Receive operations:
This handles the receiver logic, and the logic behind when to actually post messages to certain ports is contained in the Predicate and Loop Body operations. Let’s dig into the CCR code now.
Asynchronous While Loop
The first thing we need is to set up a CCR Dispatcher and a DispatcherQueue. The iodyne blog posts explain these two constructs very well. We’ll implement our code inside of the CCR machinery:
using (Dispatcher dispatcher = new Dispatcher(0, "CcrWhile"))
{
using (DispatcherQueue queue = new DispatcherQueue("CcrWhile", dispatcher))
{
// The following code snippets go here
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
}
}
Next we need to create our two ports:
Port<int> loopPort = new Port<int>();
Port<int> predicatePort = new Port<int>();
They are of type int because we’ll be passing our state (the integer counter) back and forth.
Now we need to "wire up" the receiver operations to the ports so that they will be notified when new messages are posted. We hook them up to the dispatcher queue (activate them) using static helper methods on the Arbiter class (i.e. Receive):
// Wire up the logic:
Arbiter.Activate(queue,
// Whenever the loop body needs to be executed…
Arbiter.Receive(true, loopPort,
(counter) =>
{
Thread.Sleep(100); // Simulate some long-running computation
Console.WriteLine(counter);
// Now the loop body is done, so we need to go evaluate the
// predicate again
int newCounter = counter + 1;
predicatePort.Post(newCounter);
}
),
// Whenever we need to evaluate the predicate…
Arbiter.Receive(true, predicatePort,
(counter) =>
{
Thread.Sleep(100); // Simulate some long-running computation
// Only go back and evaluate the loop body if our condition is
// met
if (counter < 10)
{
loopPort.Post(counter);
}
}
)
);
The first parameter to Arbiter.Receive is true, indicating that they are persistent receivers (as opposed to non-persistent, or one-time, receivers). The second parameter is the port to receive from, and the third parameter is the method to execute whenever a message is posted to the port. In this case, we provided the code as anonymous methods (using lambda expressions).
In plain English, we are saying "Whenever a new message (an integer) is posted to the loopPort, sleep for 100 ms, print the counter to the console, increment the counter, and send that value to the predicate for execution by posting it to the predicatePort." For the second receiver, we are saying "Whenever a new message (the integer counter) is posted to the predicatePort, sleep for 100ms and then only go back and execute the loop body again if the counter is less than 10."
At this point, we have only initialized the logic indicating what gets executed, and when. We haven’t done any real work yet, but our little asynchronous while loop contraption is ready for action. The only thing we need is an external stimulus to set it in motion.
Simple enough — let’s just post something to the predicatePort to get it started:
// Start the while loop with 0
predicatePort.Post(0);
And….away it goes! Since something new has been posted to the predicatePort, the second receiver is called, checking if the counter (which is 0) is less than 10. It is, so it posts 0 to the loopPort, then firing off the first receiver, writing the value to the console, and posting a message of 1 to the predicatePort. The cycle continues, "ping-ponging" back and forth between ports until the predicatePort has a message of 10 posted to it. The condition 10<10 is false, and another value is not posted to the loopPort. Without all ports then empty, nothing happens. The output from the program (unsurprisingly) is:
Press Enter to continue.
0
1
2
3
4
5
6
7
8
9
I know it’s a very simple example, but I think it really illustrates what is necessary to move from a sequential synchronous programs to non-sequential asynchronous programming. I’ll try to post more complex examples in the future
Working with the CCR has been really refreshing, and I’ve only touched on the surface of its capabilities. Hopefully I can dig into causalities (elegant cross-thread exception handling), iterators (writing sequential-looking asynchronously-executed code), and the other CCR primitives like Join and Interleave that let you seamlessly coordinate cross-thread access to certain pieces of code (so you don’t need to do your own locking anymore!)
Stay tuned
* I’ve copied/pasted all of his CCR posts into a single Word document as well as set up a Visual Studio project with all of the samples. If there’s enough interest (and I can get permission from NickG), I’ll make both the document and the samples available for download.
Edit: NickG has graciously allowed me to put this code up for download: Check out the download page.
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
October 5th, 2008 at 5:30 am
Hi Matt,
Please feel free to re-distribute and even amend the samples I posted up to the site. I’d just ask that you acknowledge me as the original author and link back to the website too.
I’ve done a fair amount with CCR since then, including some recent commercial work. Please contact me directly if you’d like any more info.
Thanks
Nick
October 6th, 2008 at 2:20 pm
[...] Comments Nick Gunn on Paradigm Shift – Designing Asynchronous Programs Using the CCRmatt on "Using" ReaderWriterLockSlimSteven on "Using" ReaderWriterLockSlimSteven [...]
October 30th, 2008 at 9:51 am
[...] blogged about the CCR and DSS components as part of Microsoft Robotics Developer Studio in the past. It [...]
November 17th, 2008 at 6:30 pm
[...] abstraction on top of the current threading implementations on the .NET platform. I’ve blogged about the CCR before, but haven’t really posted any useful examples that truly illustrate its [...]