You are on page 1of 1

Learn Documentation Training Certifications Q&A Code Samples Assessments More S Search  Sign in

 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?

Concurrent Affairs: Concurrency and


Learn / Archive / MSDN Magazine Issues / 2006 / September /  
Coordination Runtime

.NET Matters: Scope<T> and Article • 10/07/2019 • 30 minutes to read


More

C++ at Work: Create Dynamic Dialogs, Concurrent Affairs


Satellite DLLs, and More
Concurrency and Coordination Runtime
{ End Bracket }: Dirty Rectangles.
T October Jeffrey Richter
T November
Code download available at:ConcurrentAffairs2006_09.exe (154 KB)
T December
Contents
T VS 2005 Guided Tour

The Dispatcher Class


The DispatcherQueue Class
The Port and Arbiter Classes
The Arbiter Class
Code Examples
Coordinating Several I/O Operations
Conclusion

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.

When an application's thread performs synchronous I/O requests, the application is


basically giving up control of the thread's processing to the I/O device (a hard drive, a
network, or whatever). The application's responsiveness then becomes unpredictable.
Furthermore, when threads are suspended waiting for I/O requests to complete, the
application tends to create more threads in an attempt to accomplish more work. However,
creating, scheduling, and destroying a thread requires time and memory and can actually
hurt performance rather than improve it.

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.

Figure 1** CCR Class Hierarchy **

The Dispatcher Class

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

public sealed class Dispatcher : IDisposable { public Dispatcher(); public Dispatc

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.

The DispatcherQueue Class

After you've constructed a Dispatcher, you'll want to construct a DispatcherQueue object. A


DispatcherQueue maintains a queue of delegates that identify methods ready to execute.
The Dispatcher's threads wait for entries to appear in the DispatcherQueue. Usually, the
DispatcherQueue's queue is empty and therefore the Dispatcher's threads are waiting. As
entries appear, Dispatcher threads wake up and execute the methods:

= 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.

It is common for an application to construct its Dispatcher and DispatcherQueue objects


during initialization and use them throughout the remainder of the application's lifetime.
So, at this point, we'll turn our attention to the classes that an application tends to
construct, use for a short time, and then discard.

The Port and Arbiter Classes

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

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.

Figure 2 The Arbiter Class

= Copy

public static class Arbiter { public static ITask FromHandler(Handler handler); pu

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.

Figure 3 Common CCR Arbiters In Order From Simple To Complex

Arbiter Description

FromHandler Indicates a method that should be queued to


a DispatcherQueue. The method will just
execute. This simple arbiter is not associated
with any Port object.

FromIteratorHandler Indicates an enumerator method that should


be queued to a DispatcherQueue. Each item
enumerated identifies a simple operation that
should execute. This simple arbiter is not
associated with any Port object.

Receive Indicates a method that should be called to


process a single item from single port. The
Handler delegate takes one parameter (of the
Port’s item type).

MultipleItemReceive Indicates a method that should be called to


process multiple items from a single Port
object. The VariableArgumentHandler
delegate takes one parameter (an array of the
Port’s item type).

MultiplePortReceive Indicates a method that should be called to


process a single item from multiple Port
objects (one item per Port object; items must
be of the same type). The
VariableArgumentHandler delegate takes one
parameter (an array of the Port’s item type).

JoinedReceive Indicates a method that should be called to


process multiple items from two Port objects
(one item per Port object; items can be of
different types). The Handler delegate takes
two parameters (of the Ports’ item types).

Choice Indicates a set of methods of which only one


should execute. The CCR ensures that one
and only one of the specified methods
execute. Arbiters passed to Choice must be
non-persistent arbiters.

Interleave Indicates a set of methods that should be


called back to process items from various Port
objects. An arbiter can be part of a
TeardownReceiverGroup, an
ExclusiveReceiverGroup, or a
ConcurrentReceiverGroup. This arbiter is
similar to a reader/writer thread
synchronization lock.

The CCR ensures that a TeardownReceiverGroup


arbiter will not execute concurrently with an arbiter
from either the ExclusiveReceiverGroup or the
ConcurrentReceiverGroup. In addition, the CCR
ensures that no other arbiter will execute after a
TeardownReceiverGroup arbiter executes. Arbiters
that are part of the TeardownReceiverGroup must be
non-persistent arbiters.

The CCR ensures that an ExclusiveReceiverGroup


arbiter will not execute concurrently with an arbiter
from either the TeardownReceiverGroup or the
ConcurrentReceiverGroup. An
ExclusiveReceiverGroup arbiter is identical to a
TeardownReceiverGroup arbiter except that, once
executed, other arbiters (including itself) may execute
again in the future.

The CCR allows a ConcurrentReceiverGroup arbiter to


execute concurrently with other
ConcurrentReceiverGroup arbiters. However, the CCR
ensures that a ConcurrentReceiverGroup arbiter will
not run concurrently with a TeardownReceiverGroup
or ExclusiveReceiverGroup arbiter. Once executed, a
ConcurrentReceiverGroup arbiter will execute again
in the future.

You'll notice that some arbiters (Receive, MultipleItemReceive, MultiplePortReceive, and


JoinedReceive) take a Boolean value indicating whether the arbiter is persistent. Also, some
arbiters (such as Choice and Interleave's TeardownReceiverGroup) require that their arbiters
always be non-persistent. Understanding an arbiter's persistence is very important to
working effectively with the CCR and I will explain persistence as I walk through some code
examples.

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

private static void Msg(String format, params Object[] args) { Console.Write("Thre

Figure 4 Initialization and Shutdown in Main

= 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

private static void SpawnDemo(DispatcherQueue dq) { Arbiter.Activate(dq, Arbiter.F

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

private static void PortArbiterDemo(DispatcherQueue dq) { Port<String> stringPort

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

Arbiter.Activate(dq, Arbiter.Receive(false, stringPort, delegate(String s) { Msg("

It is important to note that calling Arbiter's Receive method simply constructs a


ReceiverTask object. This object is not registered or activated with a Port object yet.
Furthermore, there needs to be a way to tell the ReceiverTask object which
DispatcherQueue object to queue the delegate callback method to. The call to Arbiter's
Activate method does both of these things.

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.

PostArbiterDemo then posts "StringB" to the port:

= 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

Arbiter.Activate(dq, Arbiter.Receive(true, stringPort, delegate(String s) { Msg("H

MultipleItemDemo The MultipleItemDemo method demonstrates how to process Port items


in batches. In this method, I first construct a Port<String> object. Then I call Arbiter's
MultipleItemReceive method to create a ReceiverTask object that knows how to process
multiple items. The MultipleItemReceive method is similar to the Receive method except
you also pass to it the number of items that must be posted to the Port object before
processing any of them and the callback delegate must identify a method that takes an
array of items instead of a single item:

= Copy

private static void MultipleItemDemo(DispatcherQueue dq) { Port<String> stringPort

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

ThreadID=12: Ten strings=0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ThreadID=12: Ten strings=10,

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.

AsyncStreamDemo The AsyncStreamDemo method, shown in Figure 5, demonstrates how


to read data from a file asynchronously. In this method, I first construct a FileStream object
passing a file that I intend to read data from and the FileOptions.Asynchronous flag. The
FileStream class already offers methods to perform asynchronous I/O: BeginRead/EndRead
and BeginWrite/EndWrite. I have written some adapter methods that can map or translate
methods that use the CLR's Asynchronous Programming Model (APM) into the CCR's
programming model. My adapter methods are all defined in ApmToCcrAdapters that
accompanies the source code for this column.

Figure 5 AsyncStreamDemo

= Copy

private static void AsyncStreamDemo(DispatcherQueue dq) { FileStream fs = new File

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).

AsyncStreamPortSetDemo The AsyncStreamPortSetDemo method demonstrates how to


accomplish the exact same job as shown in the AsyncStreamDemo using slightly less code.
Because it is so common to use two Port objects together—one for success and the other
for failure—the Microsoft.Ccr.Core namespace defines a PortSet<T0, T1> class:

= Copy

PortSet<Int32, Exception> streamReadPortSet = ApmToCcrAdapters.Read(fs, data, 0, d

In my AsyncStreamPortSetDemo method, I define a PortSet<Int32, Exception> variable


(called streamReadPortSet) and in my ApmToCcrAdapters class I have an overload of the
Read method that internally constructs a PortSet (and its Port object members) and returns
a reference to this PortSet object.

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.

SerialAsyncDemo The SerialAsyncDemo method demonstrates how to use a C# iterator to


easily write code that performs several asynchronous operations sequentially (see Figure 6).
While these operations are performed sequentially, no threads are blocked. This gives us
the syntactical simplicity for sequential programming while allowing the application to scale
to support hundreds of thousands of pending operations.

Figure 6 SerialAsyncDemo

= Copy

private static void SerialAsyncDemo(DispatcherQueue dq) { Arbiter.Activate(dq, Arb

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.

Coordinating Several I/O Operations

The AsyncIOCoordination1 method demonstrates how to coordinate the results of several


asynchronous operations. In this method, I have a loop that issues several asynchronous
operations to request data from a Web server. As each request is made, a new
PortSet<WebResponse, Exception> object is created and returned. I then activate a Choice
arbiter on each PortSet object. Because of the way this code is written, as Web requests
complete, the proper delegate will execute indicating which operations succeeded and
which operations failed;

= Copy

for (int n = 0; n < c_ImageUrls.Length; n++) { WebRequest webReq = WebRequest.Crea

The AsyncIOCoordination2 method demonstrates another way to coordinate the results of


several asynchronous operations, as shown in Figure 7. In this method, I have a loop that
issues several asynchronous operations to request data from a Web server. In this example, I
am having all success results post to a single Port<WebResponse> object and all failure
results get posted to a single Port<Exception> object. Then I activate an Interleave arbiter.
An Interleave arbiter is similar to a reader/writer thread synchronization lock in that it can
allow multiple threads access to a resource and it can also ensure mutual-exclusive access
to a resource. When you call Arbiter's Interleave method, you pass it three arguments: a
TeardownReceiverGroup object, an ExclusiveReceiverGroup object, and a
ConcurrentReceiverGroup object. Each of these types has a constructor that takes an array
of ReceiverTask objects.

Figure 7 Coordinating Asychnronous Operations

= Copy

Port<WebResponse> responsePort = null; Port<Exception> failurePort = null; for (In

In my AsyncIOCoordination2, Interleave is passed a TeardownReceiverGroup object that has


just one ReceiverTask object. This tells the CCR to unregister the entire Interleave from all
Port objects as soon as a failure is detected on the failure Port object. In other words, if any
Web request operation fails, the CCR shouldn't process any more successfully completed
operations. I pass no ReceiverTask object to the ExclusiveReceiverGroup constructor
because my demo has no code that must execute exclusively. Finally, I pass to Interleave a
ConcurrentReceiverGroup that has one ReceiverTask object. This object tells the CCR how to
process each Web request operation that completes successfully. Because this ReceiverTask
object is in the concurrent group, multiple Dispatcher threads can execute this code
simultaneously should multiple Web requests complete at (or near) the same time.

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.

Figure 8 Coordinating Operations with a Timer

= Copy

Port<WebResponse> responsePort = null; Port<Exception> failurePort = null; Port<Da

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 .

Send your questions and comments for Jeffrey to  mmsync@microsoft.com.

Jeffrey Richter is a cofounder of Wintellect , a training and consulting firm. He is the


author of several books, including CLR via C# (Microsoft Press, 2006). Jeffrey is also a
contributing editor to MSDN Magazine and has been consulting with Microsoft since 1990

 English (United States) 0 Theme

Previous Versions Blog Contribute Privacy Terms of Use Trademarks © Microsoft 2023

You might also like