[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Dynamic composition constructs



Gerald Hilderink writes:

> A DYN PAR could be a PAR or a PRI PAR on which the parent process can add,
> remove or insert a process at run-time before running the DYN PAR.

Not with static memory allocation surely? Unless we bound the number of 
processes in some strictly checkable way. I doubt that we could do that 
without building a whole new dynamic version of occam in which
we could also pass processes down channels and much more. Pi-(calculus)-in-
the sky?


With my latest suggestion of
PRI PAR
  PRIORITY
    c ? priority
  P0
  P1
  ...
there is no notion of parent process. The channel "c" might even be connected
to one of the [P0,P1,...,PN]. 

I quite like the idea that this should be
PAR
  PRIORITY 
    c ? priority
  P0
  P1
  ...

Maybe PRIORITY should just be PRI to keep in the tradition of 3 letters, and
avoid worrying about nouns/verbs as mentioned by Oyvind. Although a noun seems
ok to me simply as a flag...


> In CTJ the PAR (Parallel), PRI PAR (PriParallel), SEQ (Sequential), ALT
> (Alternative-Guard) and PRI ALT (PriAlternative-Guard) constructs are all
> dynamic constructs. 

That has to be so in a (uncheckable?) dynamic language like Java? :-)


> Without discussing the Java implementation I will try to
> illustrate the idea by the following examples.
> 
> One can add, remove or insert processes by special methods (or by special
> operators):

> - adding process P4:   (P1 || P2 || P3).add(P4)          = (P1 || P2 || P3
> || P4)

> - removing process P2: (P1 || P2 || P3 || P4).remove(P2) = (P1 || P3 || P4)
>   or using index:      (P1 || P2 || P3 || P4).remove(1)  = (P1 || P3 || P4)
> - inserting process P2 before P4 at index 2 (index = [0..2]): (P1 || P3 ||
> P4).insert(P2,2) = (P1 || P3 || P2 || P4)

That's nice. I should have looked at what you have done in CTJ. But we can't
do that in occam for several obvious reasons. 

>
> Example:
> ~~~~~~~~

> For example PROCESS is a process,
> 
> PROCESS =	(P1 |<| P2 |<| P3 |<| P4)
> EXAMPLE =	(PROCESS.remove(P1) ; PROCESS.add(P1) ; PROCESS.remove(P3) ;
> PROCESS.insert(P3,0) ; PROCESS)	(*)
> 
> the result will be shown in steps,
> 
> PROCESS = 	(P2 |<| P3 |<| P4)            (step 1)
> PROCESS = 	(P2 |<| P3 |<| P4 |<| P1)     (step 2)
> PROCESS = 	(P2 |<| P4 |<| P1)            (step 3)
> PROCESS = 	(P3 |<| P2 |<| P4 |<| P1)     (step 4, final result)


> 
> Moving processes is changing priorities:
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> Processes could be moved from one location to the other (from a to b) by the
> move(a,b) method.
> 
> PROCESS.move(a,b) =	(p = PROCESS.at(a) ; PROCESS.remove(p) ;
> PROCESS.insert(p, b))
> with a > b.
> 
> PROCESS.move(a,b) =	(p = PROCESS.at(b) ; PROCESS.remove(p) ;
> PROCESS.insert(p, a))
> with a < b.
> 
> PROCESS.move(a,b) =	SKIP
> with a = b.
> 
> The method PROCESS.at(i) returns the process at index i in PROCESS. The
> indexes a and b are positive integer value ([0..>).

 
> Problem when executing these special methods in parallel:
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> Executing these special methods in parallel may result in illegal results,
> for example:
> 
> PROCESS =	(P1 |<| P2 |<| P3 |<| P4)
> EXAMPLE =	((PROCESS.insert(P5,1) || PROCESS.insert(P6,1)) ; PROCESS)	(**)
> the result will be
> PROCESS =	(P1 |<| P5 |<| P6 |<| P2 |<| P3 |<| P4)
> or
> PROCESS =	(P1 |<| P6 |<| P5 |<| P2 |<| P3 |<| P4)

This is just the usual concurrent write non-determinism, isn't it?
 
> Solution for Java
> ~~~~~~~~~~~~~~~~~
> The imposed restriction is that only the parent process may invoke these
> methods on PROCESS in sequence where construct (*) is valid and construct
> (**) is invalid.
> 
> The passive process interface for a Java process is
> void run()
> void add(process)
> void remove(process)
> void insert(process, index)
> void move(index_from, index_to)

 
> The parent process can never add, remove, insert or move a process when
> PROCESS is running. The action (PROCESS.add(Px) || PROCESS) is not allowed
> because when PROCESS is running then the parent process is blocked. Other
> processes are *not* allowed to have a reference to PROCESS. By following
> this simple rule makes this technique in Java secure.

In PAR
     PRI
       c ? pri
     P0
     ... 

the channel interface ensures exclusive write. And it can be done when the
processes are active: highly desirable? 
 
> General
> ~~~~~~~
> This technique also applies for the other constructs:
> - PAR construct:     (P1 || P2 || P3).add(P4)   = (P1 || P2 || P3 || P4)
> - SEQ construct:     (P1 ; P2 ; P3).add(P4)     = (P1 ; P2 ; P3 ; P4)
> - ALT construct:     (P1 [] P2 [] P3).add(P4)   = (P1 [] P2 [] P3 [] P4)
> - PRI ALT construct: (P1 [<] P2 [<] P3).add(P4) = (P1 [<] P2 [<] P3 [<] P4)
> 
> PROCESS.insert(p) on a PAR or ALT construct is equal to PROCESS.add(p).
> 
> A nice result of this technique is that processes itself have no priorities.
> One simply manipulates priorities by changing the places of processes in the
> array of processes (referred by their indexes). Indexes do not necessary
> represent the priority number of processes on composition constructs in
> general.

Thanks Gerald. That is very helpful. It gives me much more confidence that
something like

PAR
  PRI
    C ? pri
  P0
  P1
  ... 

is the right approach for occam. 

What experiences do you have with applying your primitives for real time
systems. I know that it is early days, but have any problems shown up
in applications? Do you have any robots running around your labs using these
primitives?

I don't really agree that in your system priorities are not attached to
processes just because they can be moved around a list. But since I think that
we all understand what is happening there is no point is silly discussion
about terminology.

Thanks again.

Adrian
-- 
A E Lawrence, MA., DPhil.  	adrian.lawrence@xxxxxxxxxxxxxx
MicroProcessor Unit, 13, Banbury Road, Oxford. OX2 6NN. UK.                
Voice: (+44)-1865-273274,  Fax: (+44)-1865-273275