CS452 - Real-Time Programming - Fall 2011

Lecture 19 - Servers, Courier, Warehouse

Public Service Annoucements

  1. Due date of kernel 4 (Friday, 28 October)
  2. Saturday November 5, 11.00 to 13.00. Open house for high school students.
  3. Information session on graduate studies: Tuesday, 8 November, 2011 at 16.30 in MC 2065
  4. Final exam: Friday, 9 December, 2011 at 09.30.

Anthropomorphic Programming

1. Proprietor with a Notifier

2. Using a Courier


This gets you through a bottleneck where no more than two events come too fast.

Remember that all the calls provide error returns. You can/should use them for error recovery

Another possible arrangement for task creation

Another possible arrangement for initialization

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. Using a Warehouse


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

Two issues:

  1. Handles bottlenecks of all sizes.

    Give a precise and quantitative definition of `bottleneck'.

  2. Server could be buffered on the other side

    Called a receptionist, sometimes `guard'..

What this amounts to is

Server should be lean and hungry

always be receive blocked

4. The Receptionist

We can do to the clients what the warehouse does to Notifiers.





Now should be called the President!

Doesn't actually do much work at all any more.

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, and so should you.

Worker code

  Send( administrator, nil, workOrder );
    result = work( workOrder );
    Send( administrator, result, 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.

6. 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:
    if ( request-satisfied( dbase ) ) Reply( request.tid,  )
    else enqueue( requestQ, request )
  case WORKER:
    enqueue( employeeQ, requester );
    update ( dbase, request );
    foreach request in requestQ
      if ( request-satisfied ) 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 has simply not happened.

Time-outs are needed for NOT

Who is the client of the detective

  1. Initiator of a normal action
  2. Housekeeper of the system who will clean up pathologies (Idletask?)

Debugging Real-time Programs

The most common set of debugging tools used by experienced programmers is the oldest: printf, grep & stack trace.

Debugging real-time programs, at its base, is just the same as any other debugging, and just the same as empirical science.

  1. Gather data.
  2. Create a model that explains the data
  3. Test the model
  4. If the model is not correct, go to 1.
  5. Remember that the model is ALWAYS provisional: data collected later may invalidate it, no matter how much data has confirmed it.

But real-time programs are harder to debug. Very few programs are entirely free of critical races, which are the worst type of bug, lurking for weeks months or years in seemingly correct code, the appearing when innocuous, unconnected changes occur.


Stack Trace


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.

We need methods of getting information closer to real-time

Return to: