CS452 - Real-Time Programming - Fall 2008

Lecture 10 - Inter-task Communication

Questions & Comments

Message Passing

Let's think about objects

  1. Send a message to an object, asking it to run some code for us, and return an response
  2. For the moment don't think about who actually runs the code

We normally think about this in a single threaded way, like a procedure call

  1. Call a method and block
  2. Method is just sitting, waiting for the call and immediately starts to execute
  3. When it's finished executing it returns a result.
  4. The caller is no longer blocked and continues executing.
  5. The method goes back to sitting, waiting

In an environment with multiple threads of control, which is true of your system

  1. Several threads might call the same method

    at the same time.

  2. Then the object needs to be `thread-safe'
  3. The object worries about the details

To make the last easier we make the communnication more explicit than it is in a method call

  1. To call the method a task calls Send with an argument that indicates which code is to be executed and its environment
  2. To indicate its readiness to execute the object calls Receive, which returns which code is to be executed and its environment
  3. To indicate that the code has completed its execution the object calls Reply with an argument that indicates the result of the execution
  4. Send returns within the task, with the result of the execution

Synchronization details

  1. Send blocks the caller

    Most of the time it needs the result before it can proceed further

  2. Receive blocks the callee
  3. Reply blocks nobody

What practical things can be going on in the sender?

  1. Getting some information that's needed
  2. Making a request for a service

Waiting for something


Two ways to do this

  1. Producer Sends, consumer Receives

    After Reply buffers holding data can be overwritten at will

  2. Producer Receives and Replys

    After Reply buffers can be overwritten at will.

What is the difference?

  1. If relationship is one-to-one
  2. If relationship is many-to-one
  3. If relationship is many-to-many

int Send( Tid tid, char *arg, int arg-length, char *reply-buffer, int reply-buffer-size )

These are pretty self explanatory, except

  1. The return value is the number of characters actually returned
  2. If something goes wrong, the return value is negative, coded to indicate what went wrong

    What can go wrong

    1. Illegal tid
    2. tid not an existing task

    It's up to Send to check that the reply-buffer was big enough by looking at its return value

    It's not an error if the task to which we Send never Receives

  3. Parsing argument and reply-buffer is potentially costly and error-prone
  4. This form of message passing requires user and kernel code to cooperate to avoid malignancies

int Receive( Tid *tid, char *arg-buffer, int arg-buffer-length )

These are pretty self explanatory, except

  1. How is the task id copied form kernel to receiver?
  2. What if the buffer wasn't big enough?
  3. If several tasks have Sended, which one gets Received first?

int Reply( Tid tid, char *reply, int reply-length )

These are pretty self explanatory.


Code should be constant time

Send before Receive

Receive before Send

How is the message copying done?

Return to: