Professional Documents
Culture Documents
Filter by title
With ASP.NET
7 We're 2.0updating this content regularly. Check the Microsoft Product Lifecycle for information
no longer Return to main site
about how Station:
Service this product,
What's service, technology, or API is supported.
new in System.
Xml 2.0?
Microsoft recently announced the prerelease of a new Microsoft Robotics Studio for writing
applications for robots. By itself, it is interesting to see this new toolkit, but it should have
appeal even beyond just those interested in programming robots. Under the hood,
Microsoft is powering this SDK with some very advanced technologies, including a
lightweight distributed services-oriented architecture and a common language runtime
(CLR)-based library called the Concurrency and Coordination Runtime (CCR). The CCR
makes programming asynchronous behavior much simpler than the typical challenge of
writing threaded code. This is a very significant benefit for writing robot applications
because they require handling many processes (sensors and motors) at the same time. You
should note that this column is based on a prerelease version of both Microsoft® Robotics
Studio and the CCR. All the information on these technologies is subject to change.
So why is this interesting beyond robotics? Today many applications lack responsiveness
and scalability. It is common to see applications that periodically hang and stop responding
to user input as well as server applications that do not respond to client requests in a timely
fashion. Who among us hasn't seen a Web browser time out due to a server not responding
quickly enough? The reason applications hang and have poor responsiveness is almost
always due to performing I/O operations (such as file reads/writes, Web requests, and
database queries) synchronously.
There are two main reasons why developers tend to write code that performs synchronous
I/O instead of asynchronous I/O. The first reason is because it's easier to write code that
performs synchronous I/O. When performing asynchronous I/O, the developer has to
separate the concepts of initiating the I/O request from the completion of the I/O request.
The real problem here is not the divorcing of the concepts as much as the syntax required.
The second reason is because it is hard to coordinate the actions you want performed when
the I/O requests complete.
The CCR library is a managed DLL that greatly simplifies these tasks for the programmer.
The CCR offers a number of classes allowing developers a simple object model that they can
use to easily express complex coordination patterns for dealing with completed I/O
operations. Furthermore, the CCR offers its own high-performance thread pool you can use
to execute tasks in response to completed I/O. The thread pool offers phenomenal
scalability and will maximize concurrency within your application. When you couple the CCR
with some of the new C# language features (such as anonymous methods and iterators),
you get a developer's dream come true: an easy way to write responsive and scalable
applications.
I'll describe the CCR's architecture and object model, and show numerous examples that
demonstrate how the CCR works as well as how to use it in your own applications. To
compile my demo code and to play with the CCR, you must first download it. You'll find
download information at the end of this column.
To use the CCR, there are just a few classes you'll need to become familiar with. These
classes are defined in the Microsoft.Ccr.Core namespace. Figure 1 shows the relationship
between these classes. Please refer to this figure as I describe the classes.
When your application initializes, you'll first want to construct a Dispatcher object that
creates and manages a set of threads. In effect, it is a thread pool. Like the CLR's thread
pool, these threads call methods (via delegates) in order to execute tasks:
= Copy
When you construct a Dispatcher object, you can pass to the constructor the number of
threads you desire. By default, the Dispatcher creates one thread for every CPU in your
computer. Notice that the number of threads created by a Dispatcher object is fixed; there
is no logic in the Dispatcher for dynamically creating or destroying threads. And unlike the
CLR's thread pool, there is no special thread that runs periodically checking the workload
trying to predict whether threads should be dynamically added or removed from the thread
pool. This streamlines the Dispatcher's thread pool logic and contributes to its high
performance.
When constructing a Dispatcher, you also get to set its threads' scheduling priority. By
default, the threads are created with normal priority. You can also tell the Dispatcher what
string name to give the threads that it creates. Internally, when the Dispatcher creates its
threads, it sets their Name property to your specified string. These names are used to help
debugging and can be seen when debugging you application using the Visual Studio®
debugger's Threads window.
Unlike the CLR's one-and-only thread pool, the CCR allows you to create multiple thread
pools by creating multiple Dispatcher objects. This allows you to create sets of threads (at
differing priorities, if desired) dedicated to processing certain kinds of tasks.
= Copy
public sealed class DispatcherQueue : IDisposable { // Use CLR thread pool; not Di
With the CLR's thread pool, if 1,000 items are queued up, there is no way for a new item to
be processed until all of the first 1,000 items have been extracted from the thread pool's
queue. But with the CCR you can use one DispatcherQueue object for most work items and
use another DispatcherQueue object for high-priority work items. The Dispatcher's threads
dequeue entries from all the DispatcherQueue objects associated with it in a round-robin
fashion. I should also point out that calling the constructor that doesn't take a Dispatcher
argument makes it possible to create a DispatcherQueue object that queues its tasks to the
CLR's thread pool instead of using a Dispatcher's thread pool.
A generic Port<T> object represents a queue of items, all of type T. You can think of a Port
as a way to queue an input argument to a callback method, which is analogous to the state
argument that you pass to ThreadPool's QueueUserWorkItem method.
When asynchronous I/O operations complete, their result will be posted to a Port object. I'll
explain how this happens later in this column. A Port object also has zero or more
ReceiverTask objects associated with it. When an item gets posted, the ReceiverTask objects
determine how to coordinate and process the item. In the Port<T> class definition that
follows I do not show the methods that register and unregister ReceiverTask objects
because you will not usually call these methods yourself. Instead, you will use the Arbiter's
methods to create ReceiverTask objects to register these objects with a Port object:
= Copy
public class Port<T> : /* interfaces not shown */ { public Port(); public virtual
The Arbiter class, shown in Figure 2, is what you use to tap into the CCR's coordination
features; you will use this class a lot when programming against the CCR. Arbiter is a static
class that defines a bunch of methods that are factories for creating other objects.
Specifically, when you call one of Arbiter's static factory methods, the method constructs an
arbiter that has fields that refer to one or more ReceiverTask objects that are also
constructed.
= Copy
Figure 3 shows the common arbiters offered by the CCR with a brief description indicating
what each arbiter does. Note that the CCR defines even more arbiters for less-common
scenarios. For example, there is a JoinReceiver class that calls a method when many Port
objects (of varying data types) have items posted into them. Also note that you can define
your own arbiters, but this is a very advanced feature which I won't describe here. If you are
interested in understanding arbiters more, I encourage you to examine the types in the
Microsoft.Ccr.Core and Microsoft.Ccr.Core.Arbiters namespaces.
Arbiter Description
After you've composed all the arbiters that describe your desired coordination, you must
activate the arbiters by calling Arbiter's Activate method. Calling the Active method is very
important because it registers all of the arbiter's ReceiverTask objects with the Ports and it
tells the arbiter which DispatcherQueue to post work item tasks to as Port items are
processed. If you forget to activate your arbiters, items will continue to queue up in Port
objects but they will never get processed!
As items are posted into a Port object, the registered ReceiverTask objects send the items to
their arbiter object which decides what callback method should ultimately execute to
process the posted item. The arbiter object then queues the work item task into a
DispatcherQueue, and a Dispatcher (or CLR thread pool) thread will ultimately execute the
method processing the posted item.
Code Examples
The best way to understand the CCR and how it works is to examine several code examples
while I explain what is happening. To this end, I have created a program with a bunch of
small methods in it. Each method demonstrates some part of the CCR. I will now walk
through these methods, all of which can be found in the CCRDemos.cs file in the download
for this column available from the MSDN®Magazine Web site.
Initialization and Shutdown The Main method of my example demonstrates a common way
to initialize the CCR. It simply creates a Dispatcher and a DispatcherQueue and then it
executes various methods that demonstrate uses of the CCR. The DispatcherQueue object is
passed to each demo method so that all methods use the same work item queue and
thread pool. Since the Dispatcher object is constructed in a using statement, it will have its
Dispose method called just before Main returns, exiting the application. The Dispatcher's
Dispose method tells all the thread pool threads to gracefully exit, and after they have all
exited, the Dispose method returns to its caller (Main in Figure 4). The demos make use of
some helper methods as well:
= Copy
= Copy
public static void Main() { // Creates a Dispatcher (thread pool) using (Dispatche
SpawnDemo The SpawnDemo method demonstrates how to spawn a task using the CCR's
thread pool. In my example, I use the C# anonymous method feature to define a callback
method that calls my Msg method. C# will automatically construct a delegate over this
anonymous method and that delegate is passed to Arbiter's static FromHandler method
which wraps the delegate into another object used natively by the CCR. Then Arbiter's static
Activate method is called to queue the callback method to the specified DispatcherQueue
object. This simple task spawning is similar to using ThreadPool.QueueUserWorkItem:
= Copy
PortArbiterDemo The PortArbiterDemo method demonstrates how Port and Arbiter objects
work together. In this method, I first construct a Port<String> object which internally
contains a first-in-first-out (FIFO) queue capable of holding references to String objects. A
Port object also maintains a list of registered ReceiverTask arbiter objects. Then, I call the
Post method to have the Port process a String item ("StringA"):
= Copy
When an item is posted to a port, the Post method traverses the list of ReceiverTask objects
to see if any of them want to handle the item. If no ReceiverTask objects are registered or if
none of the registered ReceiverTask objects want the item, the item is added to the Port's
internal queue. In my example, I have not yet registered any ReceiverTask objects and
therefore "StringA" is placed in the Port's queue.
The next thing the PortArbiterDemo method does is call Arbiter's Receive method which
creates a ReceiverTask object. The first argument, false, indicates that this ReceiverTask
object should not be persistent. In other words, once this ReceiverTask object processes an
item, it should not be used to process another item. The second argument, stringPort, tells
the ReceiverTask object which Port object it should be watching for items. The third
argument, an anonymous method delegate, tells the ReceiverTask object what method
should be called to process the Port's item.
= Copy
When Arbiter's Activate method is called, it registers the ReceiverTask object with the Port.
During the registration process, the Port's previously queued items are scanned. If the
ReceiverTask object wants the item, it will process it by queuing the callback delegate into
the DispatcherQueue so that a Dispatcher thread will execute the code that processes the
item.
In my example, I posted an item to the Port and then registered a ReceiverTask object.
However, it is possible to register ReceiverTask objects with a Port first and then post items
to the Port. In this case, the items are processed as they are posted and are only placed in
the queue if no ReceiverTask object wants to process it. This is very efficient.
= Copy
stringPort.Post("StringB");
Since I created my ReceiverTask object by passing false for the persistent argument, it is
allowed to process just one Port item and then the ReceiverTask object is automatically
unregistered from the Port. When the PortArbiterDemo method posts "StringB", there are
no registered ReceiverTask objects and "StringB" gets placed in the Port's queue; the string
is not displayed in the console window.
Next, I create another ReceiverTask object but this time, I pass true for the persistent
argument. Now, when this ReceiverTask object is registered with the port, it will not
automatically unregister itself and therefore it will be used to process all items currently in
the Port's queue as well as new items that get posted to the Port. So, after activating this
new ReceiverTask object, "StringB" appears in the console window, and all the items posted
to the Port via the for loop also appear in the console window.
= Copy
= Copy
In my example, I passed 10 to the MultipleItemReceive method and so the delegate will get
called once for every 10 items posted to the Port. In this example, for variety, I activated the
ReceiverTask object with the Port before I posted any items into it. I then have a for loop
that posts 50 items, causing the callback to execute five times. When I run this demo, I get
the following output:
= Copy
At this point, you should have a pretty good sense of how the pieces fit together. You
should also have a sense of the kinds of coordination the CCR allows you to pull off. The
examples so far have been pretty basic and all of them have been using just one Port object
at a time. When you really start working with CCR, you'll see that you can get quite
sophisticated and you'll frequently be coordinating items from multiple Port objects
together.
Figure 5 AsyncStreamDemo
= Copy
Basically, when you initiate an asynchronous Read operation on a Stream object, there are
two possible results: the I/O can complete returning the number of bytes read (as an Int32)
or the operation can fail, indicated with an Exception. So, in my AsyncStreamDemo method,
I create a Port<Int32> variable (called bytesReadPort) and a Port<Exception> variable
(called failurePort). Both variables are initialized to null.
Next I call my ApmToCcrAdapters type's static Read method. This Read method takes a
reference to any Stream-derived object as its first argument. I pass in the arguments that
you would normally pass to Stream's Read method: buffer, offset, and count. Then I pass in
the reference to the two Port objects. My ApmToCcrAdapters type's static Read method
internally constructs the two Port objects and then it starts the asynchronous I/O operation
by calling the Stream's BeginRead method.
When the I/O operation completes, an internal callback method (provided by my adapter
code) is invoked which checks the result. If the I/O completes successfully, then the number
of bytes read (returned from Stream's EndRead method) is posted into the Port<Int32>
object. If the I/O completes unsuccessfully, the internal method calls EndRead which throws
an exception. The internal method catches this exception and posts the Exception-derived
object it into the Port<Exception> object. So, for any single I/O operation only one of the
two Port objects will have anything posted into it.
Now I need to tell the CCR how to coordinate the possible results. To do this, I call Arbiter's
Choice method, which tells the CCR that only one of the ReceiverTask objects passed to it
should be executed. In my example, the first call to Arbiter's Receive method tells the CCR
what to execute should the asynchronous I/O operation complete successfully—its
anonymous method displays the number of bytes read and the data read from the stream
as well. The second call to Arbiter's Receive method tells the CCR what to execute should
the asynchronous I/O operation complete unsuccessfully—the Exception object's message
is displayed.
Note that when using Arbiter's Choice method, all of the ReceiverTask objects you pass to it
must have false passed for their persistent argument. That is, Choice is designed to select
one of the specified ReceiverTask objects and then all the ReceiverTask objects are
effectively unregistered from their respective Port objects. This is how the CCR ensures that
only one ReceiverTask object is chosen (which is what Choice is all about).
= Copy
The Arbiter class also has an overload of the Choice method that takes a PortSet<T0, T1>
and allows you to pass two delegates to it. This overload of the Choice method internally
calls the Choice method shown and discussed in the AsyncStreamDemo method section.
The new code is simpler than the code shown in the AsyncStreamDemo method because
you have one PortSet object instead of two Port objects and because Choice takes two
delegates instead of having to call Arbiter's Receive method twice passing in a bunch of
arguments.
I will use the PortSet in many of the following examples. I should also point out that the CCR
defines several PortSet types with variations going all the way to PortSet<T0, T1, ..., T19>.
However, PortSet<T0, T1> is by far the most commonly used.
Figure 6 SerialAsyncDemo
= Copy
The SaveWebSiteToFile method is a C# iterator method that first requests HTML data from a
Web server and then writes this data to a file. To start the operation, I call Arbiter's static
FromIteratorHandler method passing it the name of the C# iterator method.
Internally, the CCR will call into the iterator. Inside the iterator, I call one of my adapters to
make an asynchronous Web request using a WebRequest object. My adapter returns a
PortSet<WebResponse, Exception> indicating the two possible results. Then Choice is used
to tell the CCR how to deal with each of the results. The Choice method returns an ITask
object that is yield-returned back to the CCR. The CCR then activates this on the Port
objects and the CCR's thread returns to the pool waiting for the I/O operation to complete.
If the Web request fails, a message is displayed and yield break executes telling the CCR
that there are no more operations to be done. If the Web request completes successfully, a
message is displayed indicating that the application got the Web data and then the iterator
starts an asynchronous Write operation against a FileStream. Again, the result of the Choice
method is yield-returned from the iterator back to the CCR, which then activates it.
If the write request completes, you'll either see a success or failure message and then the
FileStream object will be closed. When the iterator exits, the CCR knows not to activate any
more arbiters and the sequence of operations is complete.
= Copy
= Copy
By the way, if the code that executed in response to a completed Web request were to
touch shared data, you could use a thread synchronization lock (like a Monitor or Mutex)
around the code block; however, I would discourage this. A better way to ensure that only
one thread at a time will access the shared data would be to move the ReceiverTask object
from the ConcurrentReceiverGroup constructor into the ExclusiveReceiverGroup
constructor. This way, the CCR will ensure for you that only one thread at a time can execute
the code to process a successful Web request. As you can see, the coordination aspects of
the CCR are quite powerful and easy to use once you get familiar with them. You will have
to experiment with them a bit before you really see the flexibility and control available to
you.
The AsyncIOCoordination3 method demonstrates yet another way to coordinate the results
of several asynchronous operations. This method also demonstrates how to introduce a
timer into the coordination. In this method, I create three ports: responsePort, a
Port<WebResponse> used for success results; failurePort, a Port<Exception> used for
failure results; and timeoutPort, a Port<DateTime> used for timeout.
Like the previous two examples, I have a loop that issues several asynchronous operations
to request data from a Web server (see Figure 8). In this example, I am having all success
results post to responsePort and all failure results post to failurePort. After initiating all of
the asynchronous I/O requests, I then call DispatcherQueue's EnqueueTimer method. This
call to EnqueueTimer tells the DispatcherQueue to wait 2,000 milliseconds and then to post
the current date and time into the timeoutPort.
= Copy
I next activate a Choice arbiter which ensures that one and only one of the three arbiters
passed to it will execute. The first Receive arbiter indicates what code should execute should
any Web request fail. The second Receive arbiter indicates what code should execute should
the 2,000 milliseconds expire while waiting for all the Web requests. The third arbiter, a
MultipleItemReceive, indicates what method to execute after all of the Web requests have
completed. If all the Web requests complete at the same time that the 2,000 milliseconds
expires, Choice ensures that only one of the methods will execute; you do not have to
handle potential race conditions in your code.
Conclusion
The CCR is a CLR library that provides a consistent and scalable way to program
asynchronous operations and coordinate among multiple responses. Framework Class
Library (FCL) classes that already support the CLR's asynchronous programming model
(such as Stream's BeginRead and BeginWrite) methods can easily be wrapped, allowing
existing types to integrate with the CCR so that complex failure handling and coordination
patterns can be coded in a robust, reliable, and concise way. The use of C# iterators for
scheduling operations allows sequential programming without blocking OS threads, thus
enabling scaling without sacrificing the simplicity of sequential code.
Quietly tucked away inside the Microsoft Robotics Studio, the CCR is a potent technology
that could be applied for many other applications. For more information about availability
of the CCR and other interesting technologies included in the Microsoft Robotics Studio,
see msdn.microsoft.com/robotics and the Channel 9 video on CCR development at
channel9.msdn.com/Showpost.aspx?postid=219308 .
Previous Versions Blog Contribute Privacy Terms of Use Trademarks © Microsoft 2023