CS452 - Real-Time Programming - Spring 2011

Lecture 18 - Administrator/Detective

Pubilic Service Announcement

  1. Convocation

Servers and Attendant Tasks

1. Proprietor with a Notifier

2. Using a Courier

3. Using a Warehouse

4. The Receptionist


This structure clears up most problems when a burst of requests to the server would leave the notifier waiting in a long sendQ..

What this amounts to is that servers should be lean and hungry

5. Administrator, Worker

Administrator is a proprietor who does no work but only assigns work to others

Real administrators manage workers

Most workers prefer employee status to consultant status.

Worker code

  Send( administrator, nil, workOrder );
    Send( administrator, workResult, workOrder );
    doWork( workOrder );

Administrator code


Administrator( ) {
  for ( i = 0; i < NUM_WORKERS; i++ ) worker[i] = Create( workerCode );
  for ( i = 0; i < NUM_WORKERS; i++ ) {
    Receive( *worker[i].tid, ... );
    enqueue( employeeQ, worker[i1 );
    Receive( requester, request/result );
    switch( request.type ) {
    case CLIENT:
      enqueue( orderQ, {client = requester, request} );
      if ( !empty( employeeQ ) ) Reply( dequeue( employeeQ ) ), dequeue( orderQ ) ); 
    case WORKER:
      Reply( result.client, result );
      enqueue( employeeQ, requester );
      if ( ! empty( orderQ ) ) Reply( dequeue( employeeQ ) ), dequeue( orderQ ) ); 

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

  1. As above, Administrator includes Tid of the client in the order.
  2. Worker replies to client with result and to administrator with request for another order to process.


  1. The administrator can add a little more value.

8. The Detective

Simple Events

The notifier is a task that waits on events.

You could call a notifier a detective,

Complex Events

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

  Send( part1 );
  Send( part2 );
  Send( master );


Code above doesn't even pretend to work!

Try instead

  Receive( *requester, request );
  switch( request.type ) {
  case CLIENT:
    enqueue( requestQ, {requester, request} );
    if ( happened( request, DB ) ) Reply( dequeue( requestQ ), ... );
    else foreach clue in missingInfo( request, DB ) {
      if ( ! empty( employeeQ ) Reply( dequeue( employeeQ ), clue );
      else enqueue( clueQ, clue );
  case WORKER:
    enqueue( employeeQ, requester );
    updateDB ( request );
    while ( ! empty( clueQ ) {
      if ( ! empty( employeeQ ) Reply( dequeue( employeeQ ), dequeue( clueQ ) );
      else break;
    foreach request in requestQ
      if ( happened( parsedRequest, DB ) ) Reply( request.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

  1. Initiator of a normal action

Housekeeper of the system who will clean up pathologies (Idletask?))

Debugging Real-time Programs


What does it do?

How do you get it started?

Breakpoint is a special case of a particular sort of tool that is very common.

Getting information closer to real-time.


Circular buffer somewhere

How do you write it?

  1. Write it in English
  2. Write it in code

What are the advantages and disadvantages of each?

How do you read it?

  1. From the corpse of a dead execution of the application
  2. From Breakpoint, which is probably the same thing

Use Bits

Gossip encodes its content as semantic content

One weakness of Gossip is that to go back in time very far you need a very big buffer

Use bits encode the information differently.

How do they work?

  1. Set aside a large-enough block of memory: 1 Megabyte contains 8,000,000 bits.
  2. Assign each bit to an event that interests you.
  3. Write the bit when the event occurs. (If it occurs several times assign more than one bit.)
  4. Examine the bits in a dead execution to see how far individual tasks have gotten.

Return to: