Welcome to the homepage of MC# language! MC#: Frequently asked questions (FAQ)
MC# Project
Home page 
MC# language 
Documentation 
Publications 
 Code examples 
FAQ 

 
Downloads
MC# Programming 
System
 

 
Related links
Parallel C# 
Polyphonic C# 
SKIF Project 

 
Contacts
 Contacts 


Mono powered

Microsoft .Net powered


 
   [ Ðóññêàÿ âåðñèÿ ñòðàíèöû ]    [ Version for printing ]

Frequently Asked Questions about MC#

?      What's MC# stand for?. 1

?      Today we have hundreds of different programming languages. Why do we need one more language?  1

?      What's the difference between asynchronous and synchronous methods?. 1

?      How can I execute function on remote machine/node?. 2

?      How can I return results to the main function from movable method?. 3

?      I need to wait for results that are being calculated in movable function to be ready. How can I do this in MC#?. 4

?      How can I pass some values to movable method that has already been launched?. 5

?      I need to execute some action on remote node when new message arrives in bidirectional channel. How can I achieve this?. 7

?      Is there in MC# any analogue of MPI functions MPI_iSum, MPI_fMax, etc., that allow one to calculate some summary characteristics for values being produced on numerous nodes (such as sum, average, maximum, minimum)?. 8

 

What's MC# stand for?

Multiprocessor C#

Today we have hundreds of different programming languages. Why do we need one more language?

MC# language allows write parallel concurrent programs on extension of such high-level programming language as C#. By design programs written in MC# language can work in both local and distributed modes (on cluster/GRID-network/…). The language itself abstracts programmer’s mind from the physical platform where his program will be executed in the future. Actually, when programmer is writing a program, he shouldn’t exactly know how many processors will be used by his program or which configuration will be used. All he needs to do is to mark methods, which should be executed on other processors/computers in parallel as “movable” and all low-level tasks such as moving complex memory objects from one node to another one, load balancing and etc. should be done by Runtime System.

 

What's the difference between asynchronous and synchronous methods?

Synchronous method - is a conventional method. When you call such method you have to wait until some result is returned.

In C#, conventional methods are synchronous: the caller waits until the method called is completed, and then continues its work. In the world of parallel computations, reduction of execution time of a program is achieved by transferring some methods for execution to different processors, after that a program which transferred these methods immediately proceeds to the next instructions. Methods that commonly are scheduled for execution in the different threads within single computer are called asynchronous (in Polyphonic C#) and they are declared by using the async keyword:

 

public async RedrawScreen(Graphics g) {

 // do something

}

The specific of these methods is that their call completes essentially immediately. We should note here, that async keyword is a subtype of void type, i.e. it doesn't return any value. However, the results computed by asynchronous function can be returned through its parameters, global variables or by using the out keyword. Here's the example of using asynchronous functions:

 

using System;

 

class AsyncComputeFib {

 public static void Main( String[] args ) {

  int result;

  int n = System.Convert.ToInt32 ( args [0] );

  if ( n <= 1 )

   result = 1;

  else {

   AsyncComputeFib acf = new AsyncComputeFib();

   acf.Compute( n - 1, acf.c1 );

   acf.Compute( n - 2, acf.c2 );

   result = acf.Get();

  }

  Console.WriteLine( "For n = " + n + " value is " + result );

 }

 

 int Get() & Channel c1 ( int x ) & Channel c2 ( int y ) {

  return x + y;

 }

 

 public async Compute( int n, Channel (int) c ) {

  c ! ( cfib ( n ) );

 }

 

 private int cfib( int n ) {

  if ( n <= 1 )

   return 1;

  else

   return cfib( n - 1 ) + cfib( n - 2 );

 }

}


Note that in current version of compiler it is impossible to use asynchronous methods in bounds.

How can I execute function on remote machine/node?

All you need to do is to mark it with movable keyword. For example:

 

using System;

 

public class Test {

 movable remoteFun(DateTime time) {

  Console.WriteLine(“This function was called at ” + time.ToString());

 }

 

 public static void Main(string[] args) {

  Test t = new Test();

  t.remoteFun(DateTime.Now);

  Console.ReadLine();

 }

}

 

In this example we create object t of type Test and then we launch movable-function remoteFun and pass the current system time as a parameter. As you can see, you can assign as movable function’s parameters objects of almost any .Net built-in types as well as objects of your own types. Actually, movable functions can accept as parameters objects of any classes which implement interface ISerializable. All base classes in .Net, like long, int, DateTime, string, etc. and more complicated (like Bitmap) already support this interface.

The launch of movable function completes almost immediately (asynchronously). If your program is executed in local mode, then this function will be launched in new thread. If distributed mode is applied then one of the cluster nodes will be used. That’s why there is a special Console.ReadLine() at the end of the program – otherwise program will finish executing even before the movable method remoteFun is started.

 

How can I return results to the main function from movable method?

Movable methods itself cannot return any values/objects directly. To simplify the things you can think that movable keyword is a synonym for void, but keeping in mind that movable methods can be executed on local as well as on any other processor (node, cluster) in current computational network. To return results from movable methods and to exchange data between different movable methods you should use channels (Channel). Here is the code example of using channels:

 

using System;

using System.Threading;

 

public class Test2 {

 movable remoteFun(Channel(DateTime) result) {

  while (true) {

   result.Send(DateTime.Now);

   Thread.Sleep(1000);

  }

 }

 

 Channel resultChannel(DateTime time) {

  Console.WriteLine(“Received date:” + time);

 }

 

 public static void Main(string[] args) {

  Test2 t2 = new Test2();

  t2.remoteFun(t2.resultChannel);

  Console.ReadLine();

 }

}

 

In this example we create an object of type Test2, which has resultChannel channel defined. This channel accepts only objects of type DateTime. When new object of type DateTime arrives it is displayed to the system console. Movable method remoteFun accept as a parameter a channel called result. This channel also can accept only DateTime objects. Every second this movable method sends new timestamp using this channel until Enter or Return keyboard button is pressed.

 


I need to wait for results that are being calculated in movable function to be ready. How can I do this in MC#?

MC# language uses bounds (or “chords”, in terminology of Polyphonic C#) to accomplish such tasks. Bounds combine synchronous methods, asynchronous methods (in theory… currently async keyword is not supported by MC# compiler yet) and channels with the help of ‘&’ symbol and serves as a synchronization mechanism in MC#.

General rule of chord definition: Chord consists of only one body, not more than one synchronous method and at least one asynchronous method or channel.

The body of the chord is executed only when all methods declared in the chord were called (or accordingly the messages arrived in the bounded channels). The body of the chord must return the result of the same type as return type of synchronous method in this particular chord. Example of chord definition:

 

int Get() & Channel result(int x) {

 return x;

}

 

In this example channel result and synchronous method Get are bounded in the chord. The body of the chord contains only one operator which returns the value object arrived to the channel result.

When method Get is called the following condition is checked: is there any new message in channel result? If there is no new message, then current thread (in context of this thread method Get was called) is suspended until new message won’t arrive. When new message will arrive this thread will be resumed and the body of the chord will be executed (this message won’t be added to channel’s queue).

If there were already some messages in the channel result when method Get was called then the body of the chord will be executed immediately (and one message will be read and pushed from the channel’s queue).

From the other hand, when message arrives in channel result and method Get hasn’t been called yet then this message is queued for “future use”. As soon as method Get is called message is read and pushed from this queue.

But in case if when message arrived method Get had already been called then the body of the chord is executed (and the message is considered to be read and not queued in channel’s queue).

 


How can I pass some values to movable method that has already been launched?

There is a special bidirectional channel class in MC# called BDChannel. Generally you can only send messages to conventional channels by calling Send method, while the reading from the channel occurs only when the corresponding chord is triggered. Bidirectional channels support writing operation (Send) as well as reading operation (Receive).

Example of using bidirectional channels:

 

movable ping(BDChannel bdc1, BDChannel bdc2) {

 for (int i = 0; i < 100; i++) {

  bdc2.Send(“ping…”);

  Console.WriteLine(bdc1.Receive()[0]);

 }

}

 

movable pong(BDChannel bdc1, BDChannel bdc2) {

 for (int i = 0; i < 100; i++) {

  Console.WriteLine(bdc2.Receive()[0]);

  bdc1.Send(“pong…”);

 }

}

 

BDChannel bdc1 = new BDChannel();

BDChannel bdc2 = new BDChannel();

ping(bdc1, bdc2);

pong(bdc1, bdc2);

 

This example shows how two movable functions can exchange the data amongst themselves (simple ping-pong game). It should print the following phrases 100 times:

 

ping

pong

 

And exactly in this order – first goes ping…, then goes pong…. © J

The particular feature of bidirectional channels is that they are being registered on the same node where they were initially created. If you apply bidirectional channels to movable methods then proxies of these channels will be passed, but not the copies of channels (as it happens with all other types of objects). When you call Send or Receive methods of such “proxies”, the method call is actually transferred to the node where the channel was initially registered. That means that if you send some object through bidirectional channel from node B this object is transferred to the node of initial registration A, where it is put on top of the channel’s queue. And if you will try to read from the channel by calling Receive method of the same channel on node B then the reading request will be transferred to the node A.

Remote call of the method is quite expensive operation in any system (from the point of view of performance). This should be kept in mind when using bidirectional channels. For example, the performance of previous example can be improved by minimizing the number of remote function calls in the following way:

 

movable ping(BDChannel bdc1, BDChannel bdc2) {

 // Exchange of channels

 BDChannel bdc3 = new BDChannel();

 bdc2.Send(bdc3);

 BDChannel bdc4 = (BDChannel) (bdc1.Receive()[0]);

 

 for (int i = 0; i < 100; i++) {

  bdc4.Send(“ping…”);

  Console.WriteLine(bdc3.Receive()[0]);

 }

}

 

movable pong(BDChannel bdc1, BDChannel bdc2) {

 // Exchange of channels

 BDChannel bdc3 = (BDChannel) (bdc2.Receive()[0]);

 BDChannel bdc4 = new BDChannel();

 bdc1.Send(bdc4);

 

 for (int i = 0; i < 100; i++) {

  Console.WriteLine(bdc4.Receive()[0]);

  bdc3.Send(“pong…”);

 }

}

BDChannel bdc1 = new BDChannel();

BDChannel bdc2 = new BDChannel();

ping(bdc1, bdc2);

pong(bdc1, bdc2);

 

In this example two movable methods ping and pong first of all exchange bidirectional channels among themselves (they will use these “exchanged channels” in future for data exchange). Channel bdc3 is registered on the same node where movable method ping is being executed, and bdc4 is registered on the same node where movable method pong is being executed, and that’s why the number of remote communications in this example is almost two times less than in the previous example.

 

You can find complete working sources of this example in folder “examples/pingpong/” after installing distribution package.


I need to execute some action on remote node when new message arrives in bidirectional channel. How can I achieve this?

In MC# language there is a special support of Activities to accomplish such kind of tasks.

Activity – is a special class that can listen to bidirectional channels and perform some actions when new messages arrive in these channels. Activity can subscribe to several channels simultaneously, and one bidirectional channel can be listened to by several Activities at the same time. To create your own activity you must define new activity class, inherit it from class MCSharp.Activity and override method Run. This method is called when new message arrives to one of the subscribed channels. Then you can create an instance of your activity class and register it on the channels that must be listened to. Example of using Activities:

 

public class MyActivity : Activity

{

 public override void Run(object[] parameters)

 {

  Console.WriteLine("Activity running… Received " + parameters [0]);

 }

}

BDChannel bdc = new BDChannel();

MyActivity myActivity = new MyActivity();

myActivity.Register(bdc);

for (int i = 0; i < 100; i++) {

 bdc.Send(i);

}

Console.ReadLine();

myActivity.Unregister(bdc);

 

If you run this sample it should print:

 

Activity running… Received 0

Activity running… Received 1

Activity running… Received 99

 

And if you press Enter (or Return) button on your keyboard until all 100 messages are printed then myActivity object will be unregistered and there can be a situation when bdc channel still has some unread messages in the queue.

 


Is there in MC# any analogue of MPI functions MPI_iSum, MPI_fMax, etc., that allow one to calculate some summary characteristics for values being produced on numerous nodes (such as sum, average, maximum, minimum)?

 

For this purpose there do exists a special class called BlackBoard. With the help of this class you can calculate the following functions: Sum, Max, Min, Avg and Count.

To use this class you need to follow the next steps: first of all create an object of type BlackBoard.

Constructor of BlackBoard class accepts an integer as a parameter – number of processors, each of which will produce some values for aggregation.

 

BlackBoard bb = new BlackBoard(5);

 

Then you can pass this object as a parameter to movable functions and move them to other nodes:

 

movable mfun(BlackBoard bb, int n) {

}

 

for (int i = 0; i < 5; i ++) {

 mfun(bb, i);

}

 

Afterwards you need to initialize bb (by calling Initialize method):

 

bb.Initialize();

 

During the execution of this method Runtime System exchanges the channels between main node, where initially object bb was created, and other nodes. This is made for the sake of optimization.

 

Also you need to initiate bb on all other nodes like this:

 

movable mfun(BlackBoard bb, int n) {

 bb.Initialize();

 

}

 

Class BlackBoard has a method called Send(double) for sending messages:

 

movable mfun(BlackBoard bb, int n) {

 bb.Initialize();

 for (int i = 0; i < 10; i++) {

  bb.Send(i);

 }

 

}

 

Aggregation of values (i.e. calculation of summary, maximum and minimum values and so on) is made on the node where BlackBoard object was initially created. This aggregation is made as soon as at least one value will be accepted from all launched movable methods that accepted copy of bb as parameter. Actually that means that every node can first of all send some values and then receive the same number of aggregated statistics at one time.

In order to wait for the aggregation statistics to be ready you can use the method Wait. It should be used every time when you need to use properties Sum, Max, Min, Avg, Count:

 

movable mfun(BlackBoard bb, int n) {

 bb.Initialize();

 for (int i = 0; i < 10; i++) {

  bb.Send(i);

 }

 for (int i = 0; i < 10; i++) {

  bb.Wait();

  Console.WriteLine(“Sum=” + bb.Sum + “ Max=” + bb.Max +

   “ Avg=” + bb.Avg + “ Min=” + bb.Min);

 }

}

 

If you don’t call the Wait method then you will get the same values… These values will be the same as in the first iteration of the cycle.

 

The complete example of using BlackBoard you can find after installing the distributive in folder “examples/blackboard”.

 


Âåñü Ïåðåñëàâëü