In the solution above there should be, on average,
We also know that the Warehouse will buffer messages coming and going from the hardware.
A task that can screen requests can lower the buffering required in the Proprietor. We call such a task a receptionist.
// queues & fifos
propTid = MyParentTid( );
Send( propTid( ), ..., { notifierTid, warehouseTid, courierTid }, ... );
// On return Proprietor is known to be okay
Send( courierTid, { notifierTid, warehouseTid }, ... );
// On return courier, warehouse & notifier are known to be okay
RegisterAs( ); // On return client requests can begin.
FOREVER {
Receive( &requesterTid, { request-type, message } );
switch ( request-type ) {
case COUR_RCV:
Reply( requesterTid, ... );
enqueue( rcvfifo, message );
if ( !empty( rcvQ ) ) Reply( propTid, { dequeue( rcvQ ), dequeue( rcvfifo ) }, ... );
break;
case COUR_XMIT:
enqueue( xmitQ, requesterTid );
if ( !empty( xmitfifo ) ) Reply( dequeue( xmitQ ), dequeue( xmitfifo ) );
break;
case PROP_RCV:
enqueue( rcvQ, requesterTid );
if ( !empty( rcvfifo ) ) Reply( propTid, { dequeue( rcvQ ), dequeue( rcvfifo ) }, ... );
break;
case PROP_XMIT:
Reply( requesterTid, ... );
enqueue( xmitfifo, message );
if ( !empty( xmitQ ) ) Reply( dequeue( xmitQ ), dequeue( xmitfifo ), ... );
break;
default:
Reply( requesterTid, "Sorry. I don't have any spare change.\n" );
}
}
// queues & fifos
notifierTid = Create( notifier );
warehouseTid = Create( warehouse );
courierTid = Create( courier );
receptionistTid = Create( receptionist );
Receive( &receptionistTid, ... );
Reply( receptionistTid, { notifierTid,warehouseTid, courierTid } ... );
FOREVER {
Send( receptionistTid, ..., { req-type, tid, message }, ... );
switch ( req-type ) {
case RCV:
something( tid, message );
Reply( tid, message );
break;
case XMIT:
something( tid, message );
Reply( tid, message );
break;
default:
Twiddle-thumbs( );
}
}
something( ) might be maintaining a database.
Controls a resource
Provides mutual exclusion by owning the code that accesses the resource
Proprietor provides service to clients
Like a subroutine call to the client
| Monitor | Proprietor | Comments | |
| access to resource | localized | localized | Means one at a time. |
| service model | self-service | full-service | Easily adapted to multi-core |
| service structure | subroutine of client | independent task | Easily adapted to multi-core |
| priority | client | probably different | Do we want client priority or resource priority? |
| address space | client | separate | Hardware vs software protection |
| permissions | client | different | Does client have permission to run certain instructions? |
| CPU | same | could be different | Modern hardware works hard to support threads. |
Proprietor begins processing
Can other requests be processed? Possible strategies
Generalization of proprietor
Administrator maintains an array of records
Administrator works as he can on any one of the tasks.
Real administrators manage workers
Worker( ) {
Initialize( );
Receiver ( serverPid, ... );
Reply( serverPiD )
// Avoid critical races
workResult = null;
FOREVER {
Send( administrator, workResult, workOrder );
doWork( workOrder );
}
}
Administrator( ) {
Initialize( );
for ( i = 0; i < NUM_WORKERS; i++ ) worker[i] = Create( workerCode );
for ( i = 0; i < NUM_WORKERS; i++ ) Send( worker[i], ... , ... );
// Initialize orderQueue, workerQueue
// RegisterAs
FOREVER {
error = Receive( requester, request );
switch( request.type ) {
case CLIENT:
workOrder = {client = requester, request};
if( worker = dequeue( workerQueue ) && dataAvailable( ) ) Reply( worker, workOrder );
else enqueue( orderQueue, workOrder );
break;
case NOTIFIER:
// Acquire data
// Update state
// for each queued client
// if complete data available && worker available
// workorder = {client, request}
// Reply( worker, workOrder );
// else enqueue client
break;
case WORKER:
Reply( request.client, request.result );
if( ( workOrder = deQueue( orderQueue) ) ) {
workOrder = {workOrder.client, workOrder.request};
Reply( requester, workOrder );
} else enqueue( workerQueue, requester );
}
}
}
Administrator( ) {
Initialize( );
for ( i = 0; i < NUM_WORKERS; i++ ) worker[i] = Create( workerCode );
for ( i = 0; i < NUM_WORKERS; i++ ) Send( worker[i], ... , ... );
// Initialize orderQueue, workerQueue
// RegisterAs
FOREVER {
error = Receive( requester, request );
switch( request.type ) {
case CLIENT:
enqueue ( workfifo, workorder );
while ( !empty( workfifo ) )
if ( complete ( workorder, data ) && workerTid = next( workerQ ) ) {
Reply( client, workerTid, ... );
Reply( worker, workorder );
}
break;
case NOTIFIER:
// Acquire data
// Update state
// for each queued client
// if complete data available && worker available
// workorder = {client, request}
// Reply( worker, workOrder );
// else requeue client
break;
case WORKER:
if( ( workOrder = deQueue( orderQueue) ) ) {
workOrder = {workOrder.client, workOrder.request};
Reply( requester, workOrder );
} else enqueue( workerQueue, requester );
}
}
}
The notifier is a task that waits on events.
It has two features
FOREVER {
AwaitEvent( eventId );
Send( server );
}
You could call a notifier a detective,
In an application there is likely to be lots of waiting on combinations of events.
We use the detective to discover that a complex event has occurred.
Code could be
FOREVER {
Send( part1 );
Send( part2 );
...
Send( master );
}
Code above doesn't work! Try instead
// InitializeDB;
// Create workers and synchronize;
// Synchronize with client;
FOREVER {
Receive( *requester, request );
if ( request.type == CLIENT ) {
parsedRequest = parse( request );
if ( happened( parsedRequest, DB ) ) Reply( requester );
else enqueue( parsedRequest );
}
else if (request.type == WORKER ) {
updateDB ( request );
Reply( requester );
foreach ( queuedRequest )
if ( happened( parsedRequest, DB ) ) {
dequeue( parsedRequest );
Reply( client );
}
}
}
This is the code of a detective.
We can say that an event has not happened yet.
Only at the end of the universe can we say that an event simply has not happened.
Time-outs are needed for NOT
Who is the client of the detective
R
Return to: