• No results found

3 Shadow Paging Implementation

7.5 Finale

This thesis has presented an attempt to integrate the notions of concurrency and distribution into a persistent framework in a flexible manner. The resulting architecture enables models of concurrency and distribution to be designed, constructed and executed in a persistent system. Providing concurrency and distribution as an add-on facility instead of building it into the system challenges the convention of related work. Whether or not this approach is superior is highly subjective but is founded on a conviction that a high-level solution delivers increased expressive power, safety and simplicity in the production of complex models.

It is hoped that providing this functionality has increased the expressive and modelling potential of a persistent system and that the work may broaden the appeal of persistence to a wider audience. However what metrics can one use to determine if such an approach is successful? Even if the work here becomes adopted, adapted and widely used, an argument based on popularity must by the same token decide if Cobol and C and systems such as Unix and MS-DOS should be considered successful. Whatever the outcome, the effort will not have been fruitless since the personal rewards gained from undertaking this research and tlie production of this thesis have finally convinced the author that there is a more interesting life beyond the System Manager’s Guide [Mor85-93]. A case of WTFM superseding RTFM.

Appendix A Multithreading in NapierSS

The provision of co-operating concurrency in NapierSS requires a way of expressing concurrent activity at the language level, a synchronisation primitive and a scheduler to control concurrent operation. An important point to note is that because the concurrent activities in this model interact by agreement rather than in conflict there is no need to isolate the effects of one action on the store from another. This means that the introduction of co-operating concurrency into the NapierSS system has no beaiing on the object store architecture and can be fully implemented within the language and abstract machine.

Concurrent expression in this model is provided through an abstract data type that provides a package of procedures that allow the creation and manipulation of sepai*ate threads of control. The thread package is not built into the language but is obtained through the standard environment. The standard environment is a special NapierSS environment that contains many packages of standard functions. The specification of the thread package is given in figure A.I.

type ThreadPack is abstype[ Thread ] ( start proc( proc() Thread ) ; getThreadId proc( -a Thread ) ;

kill, restart,

suspend : proc( Thread )

)

Figure A.l: Thread Package

This abstract data type contains procedures to operate on threads. For some witness type Thread the operations are

This procedure creates a new thread to execute the given void procedure, adds the thread to the list of threads, marks the thread as runnable, and returns an identifier for the thread. The thread completes when the given procedure completes.

• getThreadId : proc( -a Thread )

This procedure returns the identifier of the currently executing thread.

• kill : proc( Thread )

This procedure removes the thread denoted by the given identifier from the list of threads. If the thread is currently executing it is terminated.

• restart : proc( Thread )

This procedure marks the thread denoted by the given identifier as runnable. If the thread is currently executing tlie procedure has no effect.

• suspend : proc( Thread )

This procedure marks tlie thread denoted by the given identifier as suspended. If the thread is currently executing it is immediately suspended.

The thread package enables any number of void procedures to be executed concurrently without a change to the NapierSS language model. Threads can be nested to any depth and a thread will execute in the same environment as its parent. However there is no implicit dependency between a parent and child process; suspension or termination of one does not affect the other. The thread package is not dissimilar to the dynamic processes used in CPS-algol [KraS7]. One novelty of this approach is that in using an abstract data type the witness type cannot be discovered and hence thread ids are unforgable.

Synchronisation of Co-operating Threads

The facility for synchronisation of the threads is provided through a semaphore package shown in figure A.2.

type Semaphore is structure( wait,signal : proc() )

semaphoreGen : proc( int -> Semaphore )

Figure A.2: Semaphore Package

• semaphoreGen ; proc( int -a Semaphore )

This procedure takes an initial value for the semaphore and returns a stiucture containing procedures to operate on the semaphore.

• wait : proc()

The value of the semaphore is decremented. If the new value is less than zero then the current thread is suspended and its dependency on the semaphore is recorded.

• signal : proc()

The value of the semaphore is incremented. If the new value is less than or equal to zero, one of the threads suspended on the semaphore is selected and re-activated.

Dining Philosophers in NapierSS threads

As an example of how the threads are programmed the following listing gives a solution to tlie dining philosophers problem.

getThreadId : proc( -a Thread ) ;

kill,restart,suspend : proc( Thread )

)

type SemaphorePack is structure ( wait,signal : proc() )

type message is bool

use PS() with Library : env in

use Library with Concurrency : env in

use Concunency with threadPackage : ThreadPack ; semaphoreGen : proc( int -a SemaphorePack ) in

begin

let enter = true ; let exit = false let pickup = true ; let putdown = false use threadPackage as X[ Thread ] in begin

let Room = semaphoreGen( 4 )

let room = proc( message : message )

if message = exit then Room( signal )() else Room( wait )()

let forkSemaphore = proc( i : int SemaphorePack ) semaphoreGen( 1 )

let Forks = vector 0 to 4 using forkSemaphore

let forks = proc( i : int ; message : message )

if message = pickup then

Forks( i )( wait )() else Forks( i )( signal )()

let philosopherGenerator = proc( i : int -a Thread )

begin

let philosopher = proc() while true do

begin

! Think

room( enter ) ; ! Enter the room forks ( i,pickup ) ; ! Get one fork

forks( ( i + 1 ) rem 5,pickup ) ; ! Get two forks ! Eat

forks( i,putdown ) ; 1 Put down one fork forks ( ( i + 1 ) rem 5,putdown )

! Put down second fork room( exit ) ! Leave the room

end

! A new philosopher is bom X( start )( philosopher )

end

end let philosophers - vector 0 to 4 using philosopherGenerator end

Appendix B Atomic Transaction Package

The listing below gives a the full description of the atomic transaction package hardwired into the system. The listing is split into 5 sections with the following interpretation

• a section which maintains a binary tree of objects read and written on a per- transaction basis.

• a section which maintains the transaction data structures.

• a section which has code to handle the transaction events. This includes the code that is called from the abstract machine when an object is read or written. The code for the conflict resolution on a commit uses the conflict serializability method described in chapter 4.

• a section which describes the language level interface to the package.

• an example program of transactions on a simple bank account.

! Here are the index (binary tree) types for the pids within a transaction

type pId is int

rec type pidlndex is variant (node : Node; tip ; null)

& Node is structure (key : pid ; left, right : pidlndex)

let nilPidlndex = pidlndex (tip : nil)

rec let pidEnter = proc (k : pid; i : pidlndex > pidlndex) ÎEnter the value into the binaiy tree indexed by key

if i is tip then pidlndex (node : Node (k, nilPidlndex, nilPidlndex)) else case true of

k < i'node (key) : { i'node (left) := pidEnter (k, i'node (left)) ; i } k > i'node (key) : { i'node (right) := pidEnter (k, i'node (right)) ; i }

default : i

let pidLookup = proc (k : pid; i : pidlndex > bool)

Hookup the value in the binary Uee

begin

let head := i

Related documents