We all, most programmers included, have effective intuitions about human relations
Tasks are independent entities
Add a warehouse between the courier and the notifier.
FOREVER {
data = AwaitEvent( eventid ); // data includes event-type and volatile data
Send( warehouse )
}
FOREVER {
Receive( &requester, {req-type, data}, );
switch( req-type ) {
case courier && RCV: { Reply or enqueue }
case courier && XMIT: { Reply; buffer or Reply }
case notifier && RCV: { Reply; buffer or Reply }
case notifier && XMIT: { Reply or enqueue }
}
FOREVER {
Send( warehouse );
Send( prop );
}
FOREVER {
Receive( );
switch ( )
case courier && RCV: { Reply; buffer or Reply }
case courier && XMIT: { Reply or enqueue }
case client && RCV: { Reply or enqueue }
case client && XMIT: { Reply; buffer or Reply }
}
This structure clears up problems when the notifier runs too fast for the server.
Two issues:
Define `bottleneck'.
Called a secretary
FOREVER {
Receive( );
switch ( )
case courier && XMIT { (Reply, Reply) or enqueue }
case courier && RCV { enqueue or (Reply, Reply) }
case client && XMIT { (Reply, Reply) or enqueue }
case client && RCV { enqueue or (Reply, Reply) }
FOREVER {
Send( secretary )
Send( prop )
}
Generalization of proprietor
Administrator maintains an array of records
Administrator works as he can on any one of the tasks.
Real administrators manage workers
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: // enqueue w/o or Reply w/o
workOrder = {client = requester, request};
if( worker = dequeue( workerQueue ) && resources( ) ) Reply( worker, workOrder );
else enqueue( orderQueue, workOrder );
break;
case NOTIFIER: // or courier: Reply not, store, Reply w/o's
// 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 result, enqueue w'r or Reply w/o
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 );
}
}
}
FOREVER {
Receive
switch
case CLIENT: Reply c't or hold
case WORKER: Reply w'r, Reply held
}
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
Housekeeper of the system who will clean up pathologies (Idletask?))
Return to: