Process J - A Concurrent Language

Going Parallel


← Previous (Hello World in ProcessJ) Going Parallel Next (Communicating Processes) →

ProcessJ is a highly concurrent or parallel language. it is easy to write code that runs a number of procedures concurrently. A procedure running is called a process. To start two or more processes concurrently we use the keyword par (short for parallel). Here is a simple example that runs two processes -- hello() prints "Hello" and world() prints "World":

Two Concurrent Processes (HelloWorldPar.pj)
import std.io;

public proc void hello() {
println("Hello");
}

public proc void world() {
println("World");
}

public proc void main(string args[]) {
par {
hello();
world();
}
}

When this program is run, the hello() and the world() procedures are executed concurrently as processes; that is, they run at the same time. This means that there is no guarantee which word, "Hello" or "World", will be printed first. Since both processes run concurrently, either one could print first, so there are two different outputs from this program that are correct:

Output from
HelloWorld.pj

Hello
World

and

World              
Hello

You may see the first one most of the time when running the program, but the second one is also possible: If the scheduler on a single-core CPU schedules world() before hello(), the second output will be produced. If we slightly alter the main() procedure to look like this:

Two Concurrent Processes (HelloWorldPar2.pj)
import std.io;

public proc void hello() {
println("Hello");
}

public proc void world() {
println("World");
}

public proc void main(string args[]) {
par {
hello();
world();
}
println("Goodbye World");
}

the output of course changes to include the "Goodbye World" string. However, this string will always appear last. That is, we will see one of two possible outputs:

Output from
HelloWorld.pj

Hello
World
Goodbye World

and

World              
Hello
Goodbye World

This is because the par block (par { ... }) will suspend the main() process until all processes in the par block have finished running. If we instead wrote this code (Note, we have moved the print statement into the par block):

Three Concurrent Processes
(HelloWorldPar3.pj)

import std.io;

public proc void hello() {
println("Hello");
}

public proc void world() {
println("World");
}

public proc void main(string args[]) {
par {
hello();
world();
println("Goodbye World");
}
}

We would now be running three concurrent processes: hello(), world(), and the print("Goodbye World") statement -- all three concurrently. Now, how many possible output scenarios do we get now? Since all possible interleavings of the output are possible we get a total of 6 different output, including the ones that start with the string "Goodbye World".

It is worth noting something about a par block now: The opposite of a par block (a parallel block) is a seq block (a sequential block). We know sequential blocks from many programming languages. In Java, all blocks are sequential (if we ignore threading for a second). A sequential block is simply a number of statements separated by a semicolon inside a set of { }. This also holds true in ProcessJ, however, a sequential block may be prefixed with the keyword seq. So we could have written HelloWorldPar.pj in the following way:

Two Concurrent Processes
(HelloWorldPar4.pj)

import std.io;

public proc void hello() {
println("Hello");
}

public proc void world() {
println("World");
}

public proc void main(string args[]) {
seq {
par {
hello();
world();
}
println("Goodbye World");
}
}

This style of programming is an inherited option from the language's grandfather, a another CSP-based language from the 80ies called occam. Note, The program would be equally valid if we omitted the seq keyword, but then we may as well also remove the corresponding set of { }.


← Previous (Hello World in ProcessJ) Going Parallel Next (Communicating Processes) →