The word process has two meanings: it may denote a module of a programm or
it may denote an object of a module.
Once created a process-object may be activated. Its instructions are executed in parallel
with the instructions of other processes-objects. The word multithread execution explains
well the intuition of concurrent processes.
While the objects of classes and of coroutines share a processor,
the objects of processes do have a processor associated with each
object of process. The processor can be either a physical processor
e.g. a personal computer or workstation connected to other computers
by means of LAN network, or it may be a virtual processor, in reality
it can be an ability to acquire a time slice of a real computer.
(More or less like a process in Unix system).
The syntax of module process is similar to those of modules class or coroutine
unit {processTypeName}: {prefix} process ({formalParameters}): {declarations} begin {instructions} end {processTypeName};The present status of the processes in Loglan82 is experimental. There are several contextual restrictions imposed. Some of them are explained by the experimental and temporary status ... Some of them are not checked by the compiler. Sorry! Attention please!
call X.proced1(params)
placed in the body of a process module has an effect of communicating the calling process with the callee X.
Therefore such an instruction will be named an alien call of a procedure. We shall see later that the execution of an alien call needs a cooperation of both the calling and the callee processes.
Sorry, the compiler will not check it as an error!!!
Let Y be a process object. Let X be another process object. If a command of the following form
call X.procedr1(actual_params)
is to be executed in Y then we shall say of an allien call.
The called procedure, in this example procedr1, can be either:
Y is said a calling process, X is the callee process.
Each process has a predefined variable MASK associated with it. The value of the variable is a subset of the set of names of procedures and functions that are declared inside the process. The initial value of the MASK is the empty set . The instructions ENABLE and DISABLE can change the value of the MASK variable.
MASK={q1, ... ,qn} enable p1,p2; disable p1, p2; MASK={q1, ... , qn, p1, p2}As you see from the above diagram an instruction 'enable' adds the names to the MASK. An instruction 'disable' deletes the names from the mask. There are two other instructions RETURN ENABLE p1, ... , pn DISABLE q1, ... , qk; and ACCEPT p1, ... , pl; which modify the value of the mask. Their meaning is described below. The instruction RETURN ENABLE p1, ... , pn DISABLE q1, ... , qk; is legible in the body of a procedure or function only. The instruction ACCEPT can be put anywhere in a process module.
Let us repeat: a process can be initialised, its initialisation phase terminates when the return statement is reached. It can be given a name, say p, and it remains passive. When another proces executes the command resume(p) then the process p is activated, its actions are executed in parallel with the actions of the other active processes. Once activated it continues the execution of its commands. It may execute a stop command and become a passive process. Other processescan call for an allien call of a procedure (or function) declared in the process p. The permission to interrupt the execution of its own commands and to do a service for an external process will be granted iffthe process p is active and if the name of the called procedure is in MASK. The process can change the value of the MASK variable by means of commands enable and disable. One can use also the commands accept and return disable ... enable...
The execution of the command accept p1, ... , pn is as follows: 1° the names p1, ... ,pn are added to the MASK 2° the process waits for an allien call of a procedure listed in the MASK. When an allien call is terminated the MASK is set to its previous value, i.e. to that before the ACCEPT was executed. This is a rule with an exception: see the return disable ... enable... command below.
program First; unit writer: process(node:integer, nr:integer,s: string); var i: integer, A: arrayof char; begin return; a:=unpack(s); for i := lower(a) to upper(a) do write(a(i)); od; writeln; end writer; var w1, w2: writer, i: integer; begin w1:=new writer(0,1,"ici un texte tres long, tres long, tres long tres long tres long tres long"); w2:=new writer(0,2,"zdies otche'n dolgoj tiekst, otche'n dolgoj tiekst, otche'n dolgoj tiekst"); resume(w1); resume(w2); writeln("give me a character"); readln; end FirstWe are going now to remede the interleaving the characters. For this purpose we are going to construct a semaphore. But what it is a semaphore? Well, it is a device that allows a train to pass iff it is in a state permitting to pass and in the same moment of the passage it changes its state to blocking one. Therefore only one train is authoised to pass. In the state blocking it accepts only the demand to liberate the semaphore i.e. the state of the semaphore changes from blocking to free. By default, it is assumed that it is only the train that passed who will execute the command: liberate (when it leaves the station).
program Second; unit aSemaphore: process(node:integer); unit pass: procedure; end pass; unit free: procedure; end free; begin return; do accept pass; accept free; od end aSemaphore; unit writer: process(node:integer, nr:integer,s: string, sem: aSemaphore); var i: integer, A: arrayof char; begin return; call sem.pass; a:=unpack(s); for i := lower(a) to upper(a) do write(a(i)); od; writeln; call sem.free; end writer; var s: aSemaphore, w1, w2: writer, i: integer; begin s := new aSemaphore(0); resume(s); w1:=new writer(0,1,"ici un texte tres long, tres long, tres long tres long tres long tres long",s); w2:=new writer(0,2,"zdies otche'n dolgoj tiekst, otche'n dolgoj tiekst, otche'n dolgoj tiekst", s); resume(w1); resume(w2); writeln("give me a character"); readln; end SecondTheorem The texts shown on the screen will never be mixed. We can prove even stronger theorem that for any number of objects-processes of type writer defined as in the program Second they critical sections (here it means printing on the screen) will be executed in mutual exclusivity. Therefore with the use of semaphores one is able to assure the mutual exclusivity of critical sections of given processes. A new question appears: is it true that semaphores garantee the mutual exclusion? The answer is no, as it can be seen from the Third program.
program Third; unit Semaphore: process(node:integer); unit pass: procedure; end pass; unit free: procedure; end free; begin return; do accept pass; accept free; od end Semaphore; unit writer1: process(node:integer, nr:integer,s: string, sem: semaphore); var i: integer, A: arrayof char; begin return; call sem.pass; a:=unpack(s); for i := lower(a) to upper(a) do write(a(i)); od; writeln; call sem.free; end writer1; unit writer2: process(node:integer, nr:integer,s: string, sem: semaphore); var i: integer, A: arrayof char; begin return; call sem.free; a:=unpack(s); for i := lower(a) to upper(a) do write(a(i)); od; writeln; call sem.pass; end writer2; var s: semaphore, w1: writer1, w2: writer2, i: integer; begin s := new semaphore(0); resume(s); w1:=new writer1(0,1,"ici un texte tres long, tres long, tres long tres long tres long tres long",s); w2:=new writer2(0,2,"zdies otche'n dolgoj tiekst, otche'n dolgoj tiekst, otche'n dolgoj tiekst", s); resume(w1); resume(w2); writeln("give me a character"); readln; end ThirdThe example above reveals that one should use semaphores with rigour. It may be the case that both processes use a semaphore but due to an error their critical sections are executed in parallel causing a chaos. In most cases it would be better to conceive the architecture of the system of parallel processes as clients and servers. In the example below we create one server: ecran for serving the resourc eof screen. The processes are calling the process server asking for a service. In this case it will be printing on the screen.
program Fourth; unit ecran: process(node: integer); (* it is a server *) unit print: procedure(s: string); var i: integer, A: arrayof char; begin a:=unpack(s); for i := lower(a) to upper(a) do write(a(i)); od; writeln; end print; begin return; do accept print od (* it offers just the print service *) end ecran; unit writer: process(node:integer, nr:integer,s: string, ec:ecran); (* it is a client *) begin return; call ec.print(s) end writer; var e: ecran, w1, w2: writer, i: integer; begin e := new ecran(0); resume(e); w1:=new writer(0,1,"ici un texte tres long, tres long, tres long tres long tres long tres long", e); w2:=new writer(0,2,"zdies otche'n dolgoj tiekst, otche'n dolgoj tiekst, otche'n dolgoj tiekst", e); resume(w1); resume(w2); writeln("give me a character"); readln; end FourthTheorem The critical sections of printing the texts supplied by the processes w1 and w2 is done in mutual exclusion. ============================================================================ Example 5 In the example below we shall illustrate an asynchronous cooperation of processes. The case we are going to discuss now is as follows: there are several processes " writers ". Any of writers may print a file on a designated printer. In order to increase the throughput and in order to avoid an intermixed printing we have spoolers - one for each printer. A printer prints files taking them out of a queue.
program Five; unit writer1: process(node: integer, printer1: spooler); begin end writer1; unit writer2: process(node: integer, printer1, printer2: spooler); (* this process may print on any of 2 printers *) end writer2 unit spooler: process(node: integer); var Q: queue, f: file, tick: integer; unit print: procedure(f: file, ticket: integer); begin call Q.insert(f); if Q.full then return disable print fi; tick := tick + 1; ticket := tick; end print; begin (*spooler*) Q := new queue; return; do disable print; if Q.empty then accept print fi; f := Q.out; enable print; (* printing the file *) ... od end spooler; var s1, s2: spooler, w1, w2: writer1, w3 : writer2; begin ... s1 := new spooler(0); resume(s1); w1:= new writer1(0, s1); w2 := new writer1(0, s1); resume(s1); resume(s2); end FiveWhat are the properties of the program Five? Is it possible to obtain a mixture of texts coming from different files?