Tutorial

The following examples present some simple CTR programs and their execution. They are executed using XSB Prolog, with the CTR prototype already loaded.


  1. The following transaction program executes two non-interacting processes concurrently, where each process is a sequence of three tasks. The prototype simulates concurrency by interleaving the execution of process (a) and process(b), in a round-robin fashion. The program name is interleave2, and the contents of the corresponding transaction base and database files is as follows. 
  2. Database file  interleave2.db:

    Transaction file interleave2.ctr

    parent :- process(a) # process(b). 

    process(I) :- task(I,1) * task(I,2) * task(I,3).

    task(I,J) :- monitor(task(I,J)).

    |?-ctr_comp(interleave2). - program  is compiled

     and optimized
    yes

    | ?- exec(parent). - execution of parent goal

    committing task(a,1) - first task of process(a) commits 
    committing task(b,1) - first task of process(b) commits 
    committing task(a,2) - second task of process(a) commits 
    committing task(b,2) - second task of process(b) commits 
    committing task(a,3) - third task of process(a) commits 
    committing task(b,3) - third task of process(b) commits 

    yes 



  3. This example is a modified version of the previous program, which illustrates the role of the isolate operator, o. The isolation is used to restrict communication between processes that executes concurrently. Note that process(b) is executed in isolation. In the sample execution, process(a) begins executing, is interrupted by process(b), which executes completely, after which, process(a) continues executing.
  4. Database file interleave2a.db:

    Transaction file interleave2a.ctr:

    parent :- process(a) # o(process(b)). 

    process(I) :- task(I,1) * task(I,2) * task(I,3).

    task(I,J) :- monitor(task(I,J)).

    | ?- ctr_comp(interleave2a). - program is compiled and optimized

    yes

    | ?- exec(parent). - execution of parent goal
    committing task(a,1) - process(a) starts executing
    committing task(b,1) - complete execution of 
    committing task(b,2)    process(b) in isolation
    committing task(b,3)
    committing task(a,2) - process(a) continues its execution
    committing task(a,3)

    yes


  5. CTR executes a disjunctive goal by executing one of its disjuncts, chosen non-deterministically. The following program uses logical disjunction to choose between two sequential processes, which execute three sequential tasks each. In the sample execution, the first sequential process is executed, is forced to fail, and is undone. The second process is then executed, is forced to fail, and is undone
  6. Database file disjunction.db:

    Transaction file disjunction.ctr:

    choose :- (monitor(a1) * monitor(a2) * monitor(a3)) 
                   \/ (monitor(b1) * monitor(b2) * monitor(b3)).

    | ?- ctr_comp(disjunction). - program is compiled and optimized

    yes

    | ?- exec(choose). - execution of choose goal
    committing a1 - display from monitor showing 
    committing a2    that the ai are commited
    committing a3

    yes

    Note the use of fail in the next XSB session, to show that backtracking takes place when an execution is unsuccessful. It forces both processes to be tried. 

    | ?- exec(choose),fail. - choose will be forced to fail
    committing a1 - the ai are committed
    committing a2
    committing a3
    undoing a3 - the ai are rolled back
    undoing a2
    undoing a1
    committing b1 the bi are committed
    committing b2
    committing b3
    undoing b3 - the bi are rolled back
    undoing b2
    undoing b1
    no - all execution schedules have failed
     


  7. In the following CTR program, the parent transaction forces two interacting processes to execute concurrently while synchronizing themselves. The program starts by executing tasks from both process (a) and process(b). After executing  task(b2), process (b) waits until process (a) inserts the atom start(b3) into the database. At this point, process(b) continues, and process (a) waits until process (b) inserts start(a7) into the database. At this point, both processes continue to execute tasks. 
  8. Database file synchro.db:

    updatable start/1.

    Transaction file synchro.ctr:

    parent :- process(a) # process(b).

    process(a) :- task(a1) * task(a2) * task(a3) * task(a4) 
     

    * task(a5) * task(a6) * ins(start(b3)) 

    * start(a7) * task(a7) * task(a8).
     

    process(b) :- task(b1) * task(b2) * start(b3)

    * task(b3) * task(b4) * task(b5) * task(b6)

    * ins(start(a7)) * task(b7) * task(b8). 

    task(I) :- monitor(task(I)).

    Note that the database file declares the predicate start as updatable, so it can be updated by the rules in the transaction base file. Since the database file is not empty, it is compiled in the following XSB session. 

     
    | ?- ctr_comp(synchro). - program is compiled and optimized

    yes

    | ?- exec(parent). - execution of parent goal
    committing task(a1) - process(a) alternates with process(b)
    committing task(b1)
    committing task(a2)
    committing task(b2)
    committing task(a3) - process(b) waits for start(b3) to be
    committing task(a4)   inserted into the database
    committing task(a5)
    committing task(a6)
    committing task(b3)
    committing task(b4) - process(a) waits for start(a7) to be
    committing task(b5)   inserted into the database
    committing task(b6)
    committing task(b7) - process(a) alternates with process(b) again
    committing task(a7)
    committing task(b8)
    committing task(a8)

    yes