Dogulas

In a different thread George cleared some things up for me.

http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=2082590&SiteID=1

Specifically:

※Activate() is really a form of "spawn" or "execute in parallel", which is exactly what interleave needs, as a long running arbiter.§

This started me to wonder what actually gets put on a new thread and when does it happen. Of the arbiter objects created from the Arbiter static methods: (correct me if I*m wrong)

Receiver, JoinReceiver, and JoinSinglePortReceiver can persist or not persist at the user*s discretion.

Choice can only not persist.

Interleave can only persist.

Does it really take Activate to place an arbiter onto another thread Does that mean if you wrote:

Arbiter.Receive(true, _myPort, myHandler);

(1)That it would not be never fire Or, (2)would this hang and wait for the Receiver to complete within the current thread In this case, since the Receiver is persisted, it would never complete and the thread would be permenantly blocked.

If the first case is true and the Arbiter.Receive() method merely creates the Receiver object with the association between the port and the handler. Then it goes on it*s way and because there is no association to a DispatchQueue, the handler will never fire. If this is the case you would ALWAYS want to Activate, regardless of persistance.

If the second case is true and the creation of one of the arbiters always blocks until the arbiter is completed, then you always want to Activate any arbiter that persists. But, I don*t see anything wrong with Activating non-persisting arbiters, unless you just want to block. I think I*ve seen examples of using Arbiter.Choice() without an Activate. This makes sence if you want to block until one of several delegates fire.

If I understand correctly, the creation of the arbiter associates the handler to the port, but the Activate associates the arbiter to the DispatchQueue. If the second case is true and the creation of an arbiter does always block until the arbiter is complete, then the Activate must put the whole creation on to the new thread. In that case, if the arbiter persists, it will block the new thread and if it doesn*t, the new thread will terminate when the arbiter completes.

I believe I am starting to talk myself into the second argument. It seems to make more sence. Can anyone confirm this or blow it out of the water Either way would help.

Thanks,

Dogulas



Re: Microsoft Robotics - Concurrency and Coordination Runtime (CCR) Activate() is really a form of "spawn" or "execute in parallel"

George Chrysanthakopoulos

Hi, we actually *never*, ever, block a thread outside the internals of the scheduler. All we do, which you correctly assumed, is enqueue Tasks (and Arbiters, like Interleave, Receiver, etc are all derived from) on dispatcher queues!. The CCR has actually avery simple design: Everything is a task. Dispatcher queues queue tasks, dispatchers schedule them across N threads.

The CCR User guide clarifies all these points, please let me know if it does not





Re: Microsoft Robotics - Concurrency and Coordination Runtime (CCR) Activate() is really a form of "spawn" or "execute in parallel"

Dogulas

George,

Thanks for clearing that up. Only a Dispatcher will ever schedule a task which will cause a delegate to execute on some Thread (more than likely a different thread). Only Activate() associates the arbiter to a DispatcherQueue. Therefore each time you create one of the arbiter objects, you would need to wrap it in an Activate method.

The only exception is inside an Iterator:

Code Snippet

    void StartIterator()
    {
      // create an IterativeTask instance and schedule it
      Arbiter.Activate(_taskQueue,
        Arbiter.FromIteratorHandler(IteratorExample)
      );
    }
    /// <summary>
    /// Iterator method scheduled by the CCR
    /// </summary>
    IEnumerator<ITask> IteratorExample()
    {
      // accumulator variable
      int totalSum = 0;
      Port<int> portInt = new PortSet<int>();      
      // using CCR iterators we can write traditional loops
      // and still yield to asynchronous I/O !
      for (int i = 0; i < 10; i++)
      {
        // post current iteration value to a port
        portInt.Post(i);
        // yield until a delegate executes in some other thread 
        yield return Arbiter.Receive<int>(false, portInt, delegate(int j)
        {
          // this delegate can modify a stack variable, allowing it
          // communicate the result back to the iterator method
          totalSum += j;
        });
      }
      Console.WriteLine("Total:" + totalSum);
    }

In this case we see "yield return Arbiter.Receive ...". Does this mean the yield return implicitly does the same thing as Arbiter.Activate

Thanks,

Dogulas





Re: Microsoft Robotics - Concurrency and Coordination Runtime (CCR) Activate() is really a form of "spawn" or "execute in parallel"

Dogulas

George,

I'm sure it has to do with this passage that I found in the CCR User Guide, CCR Iterators, near the bottom of Example 18.

Code Snippet

yield return Arbiter.Receive<int>(false, portInt, delegate(int j)
{
The yield return statement above returns control to the CCR scheduler. It also returns an instance of the ITask interface, implemented by the ReceiverTask created when calling the Arbiter.Receive helper. The CCR scheduler activates the returned Task and also associates the iterator with the task. When the task completes execution, it can choose to progress the iterator to the next code statement after the yield. When the programmer thinks about this code, they can think of the yield as a synchronization point: the iterator method will stop execution until the yield is satisfied.

I thought the Dispatcher class did the scheduling. Is this CCR scheduler some kind of singleton object that the Dispatcher hands things off to Does this mean the yield return bypasses a Dispatcher and goes directly to this CCR scheduler

Thanks,

Dogulas





Re: Microsoft Robotics - Concurrency and Coordination Runtime (CCR) Activate() is really a form of "spawn" or "execute in parallel"

Rob Sim -- Braintech

Hi Dogulas,

There is an important distinction between Activate and yield return: Activate will create a task, put it on the queue, and return immediately (ie probably long before the task begins execution). Conversely, yield return creates a task, puts it on the queue, and blocks execution of the calling method until the task completes. So, in your example IteratorExample will block at each yield return until the delegate returns.

In classical concurrency thinking, if you were to use activate instead of yield return in your example, you'd have problems with race conditions on updating totalSum (+= is not an atomic operation and the spawned tasks could run simultaneously on different threads), and you could wind up with an incorrect final value. I don't know enough about the CLR to say with confidence that this is an issue in C# but combining a race condition with any sufficiently more complex operation would likewise cause you all kinds of headaches.











Re: Microsoft Robotics - Concurrency and Coordination Runtime (CCR) Activate() is really a form of "spawn" or "execute in parallel"

Dogulas

Rob,

Hey, thanks for the reply! I was aware of the blocking behavior of yield return and the problems I would incur in a truely parallel environment.

The question I really had was the underlying mechanism. I understand that Arbiter.Recieve() returns an arbiter class which is a type of task. By itself, it doesn't do anything and must be "scheduled". In all other examples of arbiter class creation, the resulting arbiter is passed to Arbiter.Activate() so that a Dispatcher can schedule it on some thread.

What happens behind the scenes when you yield return on a simple arbiter class I know it blocks, but how does it get scheduled Does it go through a Distributer behind the scenes How does the "CCR scheduler" mentioned in the documentation relate to a Distributer

Dogulas





Re: Microsoft Robotics - Concurrency and Coordination Runtime (CCR) Activate() is really a form of "spawn" or "execute in parallel"

Dogulas

Ok. I'm going to take a stab at this. Please feel free to shoot holes in it.

Dogulas

An iterator is a section of code that returns an ordered sequence of values of the same type. The way iterators are used in CCR is as the body of a method and the value returned is of type ITask.

When calling an iterator block you are asking it to return those values one at a time. Typically you would process each returned value with a foreach statement. If the iterator block were a method named ※GetEnumerator()§, you could use the object name directly.

Code Snippet

static void Main()
{
myClass myObj = new myClass();
foreach ( i in myObj ) { Debug.Writeline(i); }
}
public class myClass
{
private IEnumerator GetEnumerator()
{
For (int i = 0; i < 5; i++) { Yield return i; }
}
}

Within the iterator block, each time the yield return is encountered, the specified object is passed back to the calling foreach statement. Execution is suspended in the iterator method and is transferred to the code block of the foreach statement. When the foreach statement is completed, execution is transferred back to the next statement in the iterator block. This will continue until the iterator block completes or encounters a yield break statement. At that point execution is transferred to the next statement in the calling method after the foreach code block.

In CCR, you would seldom call your iterator method ※GetEnumerator()§. In this case, you would simply use the method call in the foreach statement. Such as ※foreach (i in myObj.myIterator()) {#}§.

The way iterators are used in CCR is to iterate through a number of tasks. Therefore the return value of the iterator method will be a generic version of IEnumerator. Specifically, IEnumerator. Because of this in your yield return statements you can only return a task object or any of the arbiter objects which are specialized tasks and implement ITask.

The way that the iterator method is called in CCR is by using the any of the helper functions that return a task object from an iterator, such as Arbiter.FromIteratorHandle() or Arbiter.ReceiveWithIterator(). These are wrapped in a call to Activate so that each task will in turn be given to the Dispatcher referenced by the Activate call.

Code Snippet


void Startup()
{
Dispatcher dispatcherAlpha = new Dispatcher(0, "first dispatcher");
DispatcherQueue taskQueueAlpha

= new DispatcherQueue("first queue", dispatcherAlpha);
Arbiter.Activate(taskQueueAlpha,
Arbiter.FromIteratorHandler(MyIterator));
// more code ...
}

IEnumerator<ITask> MyIterator()
{
Port<int> port = new Port<int>();
yield return Arbiter.Receive<int>(false, port, delegate(intj) {return j;}
for (int k = 1; k < 5; k++)
{
yield return Arbiter.Receive<int>(false, port, delegate(int k) {return k;}
}
}

In this example, the single yield return and each of the four yield returns in the loop will return an arbiter (ITask) to the point that the iterator was called. Therefore each of these tasks will be scheduled by dispatcherAlpha.

When the Activate call schedules a task from the iterator, it will pause and wait until that task is complete before getting another task from the iterator to schedule. Because of this, there is a requirement that the tasks NOT be persisted. A persisted task never reaches a complete state. Since the Interleave arbiter can only be created as persisting, it cannot be dispatched it this way.

If all this is correct, then the CCR scheduler mentioned in the CCR User*s Guide, CCR Iterators must be a synonym for Dispatcher.





Re: Microsoft Robotics - Concurrency and Coordination Runtime (CCR) Activate() is really a form of "spawn" or "execute in parallel"

Nick Gunn

Douglas hi,

My understanding is that the iterator functionality does *not* block - it simply defers calling MoveNext() until the yielded task (be that an arbitration or whatever) has fully completed. This has the effect of logically pausing the execution of the method, without *ever* blocking (or pausing) the thread.

Once the yielded task has been prepared, the thread will mostly likely go off and do something else, i.e. you could in principle get a different thread executing between each yield in your iterator method.

<shamelessplug>

I blogged about this a month or so ago, if it helps.

</shamelessplug>

Nick.





Re: Microsoft Robotics - Concurrency and Coordination Runtime (CCR) Activate() is really a form of "spawn" or "execute in parallel"

George Chrysanthakopoulos

When i say CCR scheduler, you should read CCR Dispatcher, sorry for the confusion. They are the same thing.





Re: Microsoft Robotics - Concurrency and Coordination Runtime (CCR) Activate() is really a form of "spawn" or "execute in parallel"

George Chrysanthakopoulos

Hi i cant really disclose how we do iterator scheduling. Its actually not that complicated and the CCR guide (which you quoted earlier) explains what happens.

Again, we only "logically" block your iterator method, no thread is blocked. This allows you to have millions of pending iterators, waiting on I/O....





Re: Microsoft Robotics - Concurrency and Coordination Runtime (CCR) Activate() is really a form of "spawn" or "execute in parallel"

Dogulas

Thanks guys,

Nick, that is a great writeup in your blog. Very clear and consise. It helped a lot. By the way, the name is Dogulas. The bank screwed up the spelling, but I liked it so I kept it. ;-}

George, Thanks for clearing up the terminology. I'm just going to trust you on this non-blocking-deferred-calling secret thingy that you do.

I did a little test to see what code was ending up on which thread and was quite surprised by the results. I'll include the code at the bottom so you won't have to wade through it if you don't want to. Appearantly there is some magic in the FromIteratorHandler method. I would have guessed the iterator processing would be dealt with on the main thread and only the scheduling of the delegates would be shifted to the threads managed by the Distributor. Instead, the FromIteratorHandler method returns almost immediately and any code in the iterator method as well as the scheduled delegates seems to be placed randomly on the Distributer managed threads. Furthermore, code before and after a yield return statement may easily end up on different threads.

True to your word, however, all the code in the iterator method including the delegates function in a top down manner, regardless of the threads they are on. The following code sample would return:

Main Thread: 9

finished Main Thread: 9

Iterator Thread: 11

DelegateA Thread: 11

Iterator Thread: 11

DelegateB Thread: 12

Iterator Thread: 12

DelegateC Thread: 12

Iterator Thread: 12

Over several runs the iterator threads and the delegate threads are alway some random combination of 11 and 12. If I comment out the line "portB.Post(2);" so that portB is empty, then the "DelegateB Thread" line and all following lines are never printed. I guess I was surprised that the iterator code was also being scheduled. That may not be technically correct, but it seems as if it is being scheduled.

Here is the code:

Code Snippet

private void StartIterator()

{

Dispatcher dispatcher = new Dispatcher();

DispatcherQueue taskQueue = new DispatcherQueue("demo", dispatcher);

Console.WriteLine("Main Thread: " + Thread.CurrentThread.ManagedThreadId);

Arbiter.Activate(taskQueue, Arbiter.FromIteratorHandler(MyIterator));

Console.WriteLine("finished Main Thread: " + Thread.CurrentThread.ManagedThreadId);

}

private IEnumerator<ITask> MyIterator()

{

Port<int> portA = new Port<int>();

Port<int> portB = new Port<int>();

Port<int> portC = new Port<int>();

portA.Post(1);

Console.WriteLine("Iterator Thread: " + Thread.CurrentThread.ManagedThreadId);

yield return Arbiter.Receive<int>(false,

portA,

delegate(int x)

{

Thread.Sleep(1000 * x);

Console.WriteLine("delegateA Thread: " + Thread.CurrentThread.ManagedThreadId);

});

portB.Post(2);

Console.WriteLine("Iterator Thread: " + Thread.CurrentThread.ManagedThreadId);

yield return Arbiter.Receive<int>(false,

portB,

delegate(int x)

{

Thread.Sleep(2000 * x);

Console.WriteLine("delegateB Thread: " + Thread.CurrentThread.ManagedThreadId);

});

portC.Post(3);

Console.WriteLine("Iterator Thread: " + Thread.CurrentThread.ManagedThreadId);

yield return Arbiter.Receive<int>(false,

portC,

delegate(int x)

{

Thread.Sleep(3000 * x);

Console.WriteLine("delegateC Thread: " + Thread.CurrentThread.ManagedThreadId);

});

Console.WriteLine("Iterator Thread: " + Thread.CurrentThread.ManagedThreadId);

}





Re: Microsoft Robotics - Concurrency and Coordination Runtime (CCR) Activate() is really a form of "spawn" or "execute in parallel"

George Chrysanthakopoulos

The CCR (and me) does not want its users to think about threads. The CCR user guide should be more explicit but unless you want tight thread affinity for legacy interop reasons, always assume tasks, including tasks you yield to from an iterator will run on *arbitrary* thread context. You should basically not care what thread executes your task.

The CCR dispatcher will load balance as it sees fit to maximize CPU utilization across all cores/processors.

Your example only ever has one task running so the CCR picks up an available thread at random (its a pure race between threads).

thanx

g