CS452 - Real-Time Programming - Spring 2015
Lecture 22 - Anthropomorphic Programming
Public Service Annoucements
-
Train Control I demo on Friday, 3 July.
-
The exam has three start times.
-
20.30, August 4
-
09.30, August 5
-
20.30, August 5
The end times are 26.5 hours after the start time.
Answers to questions asked from 20.30, 4 August to 22.00,
4 August will be answered on the newsgroup, whether they
arrive by e-mail or on the newsgroup.
-
Where on the continuum from human to inanimate to people
perceive computers to be?
Anthropomorphic Programming II
Servers and Attendant Tasks
2. Using a Courier
Transmit Notifier Code
Transmit Courier Code
Transmit Proprietor Code
- Initialize
// queues & fifos
notifierTid = Create( notifier );
courierTid = Create( courier );
Send( courierTid, notifierTid, ... ); // On return courier & notifier are known to be okay
RegisterAs( ); //On return client requests will begin.
Notes
Another possible arrangement for task creation
- Server creates the courier
- Couier creates the notifier
Another possible arrangement for initialization
- Server Receives
- Courier receives.
-
Notifier sends to its ParentTid.
-
Courier replies to Notifier.
-
Courier sends to its parentTid
-
Server replies to Courier.
Distributed gating
I am showing you collections of tasks implemented together because sets of
related tasks is a level of organization above the individual task.
E.g., the decision to add a courier requires revision of code within the
group, but not outside it.
3. The Warehouse
4. Secretary, Receptionist
The warehouse guards the notifier from the effect of multiple
clients on the server. Another method of guarding the notifier
is to guard the proprietor so that its sendQ is always empty. The
secretary/receptionist does so.
The secretary receives requests from many clients and forwards
them one at a time to the proprietor. Because the secretary
Receives it cannot Send. It communicates with the Proprietor using
a Courier.
- The Courier Sends to the Secretary.
- The Secretary Replys the next request to the Courier.
- The Courier Sends the request to the Proprietor.
- The Proprietor Replys the result to the Courier.
- The Courier Sends the result to the Secretary.
- The Secretary Replys the result to the Client.
Notes
-
When all the clients have been given service
- The Secretary is Send-blocked waiting for a Client.
- The Courier is Reply-blocked waiting for a request from the Secretary.
-
The Proprietor is Send-blocked waiting for either data
from the Notifier or for a request from the Courier.
- The Notifier is Event-blocked.
-
The Courier is almost always Reply-blocked. If it spends a
significant amount of time Receive-blocked the system is
overloaded.
-
If there is a temporary overload of Client requests, the
Courier may sit for a while in the Secretary's SendQ while
the Proprietor continues to interact with the Notifier.
-
If there is a permanent overload of requests you are in
trouble.
5. Administrator, Worker
Administrator is a proprietor who does no work but only assigns
work to others
-
Work orders are given to workers
-
If Create is fast and you have a method for reclaiming resources you
can Create and Destroy workers on demand.
-
Otherwise workers are created at initialization and the administrator
maintains a pool of free workers
-
each free worker is a REPLY-BLOCKED task
Where do the workers come from?
- Static organizations hire a workforce of employees who are assigned
tasks as they come up.
- And if they have run out of employees then you (the client) just
have to wait.
- If the worker is waiting for some data to be available, which is
the most common case, then
- a worker at the priority of the client does the waiting,
- the administrator goes on to supply workers to other clients,
- nobody loses
- Dynamic organizations hire workers after the need for work appears, and
fire them when the work is done. These are called contract workers or
consultants.
- Create (hire) a worker when they are needed, destroy (fire) them
when they are no longer needed.
- No need to provide a pension, benefits and so on.
- Helpers hired (created) by the consultant should be fired
(destroyed) with the consultant.
- The destroy primitive usually destroys all the children of the
task being destroyed.
- Resources are returned to the system to prevent a population
explosion of zombies in the workplace
- Semi-dynamic organizations are between static and dynamic.
- New workers are hired (created),
- but they are not fired.
- If two dynamic administrators exist in a system you may have to
regulate the system globally in order to resolve a creation race
between them.
- The type of independent agent system studied by Kate Larson handles
such problems locally
Most workers prefer employee status to consultant status.
Worker code
Send( administrator, nil, workOrder );
FOREVER {
Send( administrator, workResult, workOrder );
workResult = doWork( workOrder );
}
doWork
might require further sends to servers or warehouses,
which is harmless in this context.
What kind of work might a worker do?
- The most common type of worker does something like calculating a
shortest route.
- Too long a calculation to put inside a server, but something that a
client might request from a server.
- Updating a calibration might fall into the same category.
- You certainly want to do it, but it doesn't matter if you do it
after more urgent things.
- The results that come back from workers will not preserve the order
in which they are given.
- It might even do floating point calculation. Why?
Administrator code
Initialization
Administrator( ) {
for ( i = 0; i < NUM_WORKERS; i++ ) worker[i] = Create( mypriority - 1, workerCode );
FOREVER {
Receive( requester, request );
switch( request.type ) {
case CLIENT:
enqueue( orderQ, {order = {client, request}} );
if ( !empty( employeeQ ) ) Reply( dequeue( employeeQ ) ), dequeue( orderQ ) );
break;
case WORKER:
enqueue( emploeeQ, requester);
if ( !empty( orderQ ) ) Reply( dequeue( employeeQ ), { dequeue( orderQ ) );
if ( request != nil ) { Reply( request.client, request.request );
break;
}
}
Note: Tid of the client is included in the workorder to the administrator
does not have to maintain and search a list of jobs being done.
(Administrators are by nature lazy!)
Alternative Worker/Administrator Model
- As above, Administrator includes Tid of the client in the order.
- Worker replies directly to client with result and to administrator with
request for another order to process.
Comments
- The administrator can add a little more value.
- Suppose that there is data required for processing each order.
- The administrator could receive it from a notifier or courier.
- It would be maintained internally and added to the appropriate
order before the order is despatched to the worker.
- Another model: the worker queries a detective.
6. The Detective
Simple Events
The notifier is a task that waits on events.
- AwaitEvent is like Send
It has two features
- a simple, kernel-defined event that it waits on
- hardware/kernel is like Receive/Reply
- can only serve one master (`one' defined in terms of the kernel
events)
- The notifier needs to pass on that the event has happened
You could call a notifier a detective,
- who looks around on your behalf,
- and let's you know when something you care about happens,
- but really it is a detective's worker, whom you employ directly.
Complex Events
In an application there is likely to be lots of waiting on combinations of
events.
- form the combinations using Boolean operators
- for example, Respond `okay' when this sensor is triggered or `time-out'
when Delay returns.
We use the detective to discover that a complex event has occurred.
- How does the detective work?
Conjunction
Code could be
FOREVER {
Send( part1 );
Send( part2 );
...
Send( master );
}
Disjunction
Code above doesn't even pretend to work!
Try instead, something like
FOREVER {
Receive( *requester, request );
switch ( request.type ) {
case CLIENT:
case = {requester, request.event, request.delay} );
insert( caseDB, case );
if ( !empty( delayQ ) && !empty( irregularQ ) ) {
Reply( dequeue( delayQ ), case );
Reply( dequeue( irregularQ ), case );
}
case DELAY:
enqueue( delayQ, requester );
if ( case = pending( caseDB, nil ) && !empty( irregularQ ) ) {
Reply( dequeue( delayQ ), case );
Reply( dequeue( irregularQ ), case );
}
case = extract( caseDB, request.requester );
if ( case != nil ) Reply( case.requester, TIME_OUT );
break;
case CLUE:
enqueue( irregularQ, requester );
if ( ( case = pending( caseDB, nil )!=nil && !empty( delayQ ) ) {
Reply( dequeue( delayQ ), case );
Reply( dequeue( irregularQ ), case );
}
case = extract( caseDB, request.requester );
if ( case != nil ) Reply( case.requester, EVENT );
break;
}
}
This is the code of a particular detective, one that notifies you which
occurs first, a time-out or an event.
Not
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: how to do them is shown above.
Who is the client of the detective
- Initiator of a normal action
7. Housekeeper
Housekeeper of the system who will detect, and possibly clean up
pathologies.
-
The housekeeper is usually the idle task, which should not
block.
-
Cleaning up usually requires tasks to be destroyed/created.
How, then, can it create or destroy tasks?
-
The same question occurs, even more strongly, when the idle
task wants to tell the user to do something.
8. The Grim Reaper
Most often pathologies are handled by destroying one or more
tasks, the recreating them. Destroying is usually done in the
context of programming conventions. One convention followed here
is that when tasks work together as a unit task creation is done
internally with one master task directly or indirectly creating
all tasks in the unit. Then
-
Destroy only the master task.
-
Destroy is implemented to destroy all the children of the destroyed
task.
-
Creating the master task puts everything back together.
Resources must be returned for reuse. Some are easy.
-
Resources owned by the kernel, such as memory, tid and TD are
easy for the kernel to handle.
Others are hard. Suppose a task owns a piece of track. It must
be given back or your project won't survive very much task
destruction.
-
The kernel doesn't know about this resource ownship. Who does?
-
The task itself. Can you give it some sort of Java-like
destructor?
-
Then you would need the task to commit suicide. But what if
it is not runnable?
-
The task that gave out the resource. Might the kernel or the
name server have a list of tasks that give out resources,
each of which is notified. (Our kernel might be putting some
weight.
How do we keep the time for this process bounded above?
Return to: