Cind language documentation

Concurrent expressions

Concurrent block

Concurrent block {# ... } executes a number of concurrently worked threads and then waits until all of them ends.
Threads are separated by hash character ( # ).
First two characters of concurrent block ( {# ) must be written together, without space or any other separator
(because otherwise statement will be interpreted as a regular block of instructions).
Instructions of one thread can be separated by semicolon characters, just like in the block of code.
Example:

{# host.print("A"); # host.print("B"); # host.print("C"); }

This instruction starts three threads, each of them will print out different character,
what can result in writting out one of six different sequences: ABC, ACB, BAC, BCA, CAB or CBA, with equal probability.

In fact, process of the execution of concurrently worked threads most depends on the environment,
where Cind program are executed and on the software that manages its execution.
For instance, it depends on the number of cores in the phisical processor that executes program.
If there will be less free cores than executed threads, then they will be executed in parts in random order.
There is no way to know which thread will start firstly, which one ends last, which will be executed in parts, etc.,
so it's better to assume that everything could happen, and everything that can happen is equally probable.

The result value returned by a thread is a value from its last instruction, or a value returned by instruction return during execution (which will stop calling thread, but won't stop all concurrent block).
The result returned by concurrent block is the result from the last ended thread.
For example, in this sentence:

x = {# true # false };

there are two threads returning true and false, there is 50% chance that x will be true and 50% chance that will be false,
because it is not known which one of those two threads will ends last.

Syntax of concurrent block also allows to execute a number of copies of given thread.
Number of copies must be putted in brackets [ ... ] after hash character ( # ).
For example, this code:

{#[5] x++; f(x); };

executes five concurrent threads, each of them makes: { x++; f(x); }.
Another example:

{# f(x); #[n] g(y); #[n+1] h(z); };

will execute one thread making f(x), n threads making g(y) and (n+1) threads making h(z), all of this 2n+2 threads will be executed together and concurrently.
Value putted inside brackets [ ... ] is maped to int type during evaluation, and must be greater than zero, otherwise there will be an exception thrown.

When exception is thrown by some thread, a concurrent block will firstly wait for other threads to stops, and after that, this exception will be thrown out from the concurrent block.
If more then one thread throws an exception, then concurrent block will throw only first received exception, and the rest of them will be lost.

Separate thread

Separate thread statement {* ... } will execute one thread concurrently and will not wait for its end.
Instructions of thread can be separated by semicolon characters.
Example:

f(1); {* f(2); f(3); }; f(4);

In above code, there are two threads, one of them executes f(1), then fires the second thread, in place of declaration, without waiting for it, and finally executes f(4) concurrently to the second thread. The second thread executes f(2) and f(3) concurrently to the first thread.

The separate thread inherits context from the place of declaration, including visible variables, special objects and binded values.
The result returned by separate thread is being omitted, and any exception throwed out from the thread will be lost.
There is no method to stops working thread from the outside, except the situation when whole program is being terminated or suspended.

Incidentally, another way to start independent thread is to create object of selector class (see Selector class).

Accessing variables

Threads can access all variables, which are visible from the code (see Variables), and can access them concurrently.
In example:

int x = 0; {# x++; # x--; # host.println(x); }

there are three concurrent threads, which are accessing the same variable x.
That code will result in printing out number -1, 0 or 1.

Reading and writing to variables are the only atomic instructions in Cind language.
Even variable increment operator ( x++ ) is not an atomic operation, and may be divided into steps (e.g. to reading value, increment and then writing them back), which can be interleaved with other variable accessing instructions from some other concurrently worked thread.

Synchronization methods

Monitor class and selector class are the primitive mechanisms to provide sychronization between concurrently worked threads.
Monitor provides exclusive access to internal code, using execute locks and conditions (see Monitor class);
while object of selector class has own thread, who can accept incoming messages in own way and order (see Selector class).
Typical synchronization toys, like semaphores, mutexes, lock sections, etc., can be implemented as an objects of monitor or selector class.



Cind programming language 1.0.4

 

Advertisements