(Latest Revision: Mon Nov 5 19:45:09 PST 2001 ) heapifyAsg

heapifyAsg



//////////////////////////////////////////////////////
CS 3750  Second C Programming Assignment  (prog #2)
//////////////////////////////////////////////////////

Before starting this assignment, read the file heapsort.pas to
review what is involved in a heapsort.  Specifically, it is the
intial heap-building activity (heapification) that is the subject
of this assignment.  File heapsort.pas is written in the Pascal
programming language.  I'll give you some tips for how to read
it.

Use queuing semaphores to implement a "parallel heapification"
program that turns a complete binary tree with 31 elements into a
heap.  Below you see a depiction of a 31-element binary tree.

                               *
               *                               *               
       *               *               *               *       
   *       *       *       *       *       *       *       *   
 *   *   *   *   *   *   *   *   *   *   *   *   *   *   *   * 


From reading heapsort.pas, you can learn all the details of what
a heapification algorithm *does*, but please keep in mind that
the code in heapsort.pas is very *unlike* the code you need to
write for a *parallel* heapification.

I want your program to have a separate thread to play the part of
each internal node in the tree.  The mother thread can play the
role of the root node, if you like.  That leaves 14 threads to be
created by the mother to assume the roles of the other internal
nodes.  You can have threads to play the roles of the leaf nodes
if you want, but you don't have to.

The threads must communicate using shared semaphores and
variables.  Semaphores implemented by sem.cpp and sem.h are the
only synchronization primitives you are allowed to use in this
program (with the sole exception of a mutex_t called stdoutLock
for locking standard output, as you were allowed in the last
program.)

Each internal node-thread will be responsible for starting and
propagating "waves" of re-heap-down activity from the node that
it represents.  It will be responsible for receiving information
about completed operations from child nodes, and for using
information received as a basis for sending information on to its
parent.


                             P
                              \
                               \
                                \
                                 A
                                / \
                               /   \
                              /     \
                             L       R


The communication between the threads could be done solely with
semaphores.  In this mode, it would be best to use different
semaphores for different messages to make it easier for the
programmer and others (i.e. me) to understand the logic of the
program.  For example there could be semaphore arrays
NeedReHeap[] and ReHeapDone[] set up so that each internal node
has one element of each array associated to it.  A process would
SIGNAL on the semaphore of another process when it wants to send
a message.  For example, L could SIGNAL on ReHeapDone[A] when it
wants to tell A that the subtree rooted at L is now a heap.
Conversely, A could WAIT on ReHeapDone[A] when it needs to
receive that message.

Another modality is for communication between the threads to be
primarily done through a simplified message-sending interface,
possibly implemented by an array of message buffers:
myMessages[], appropriately protected by semaphores in such a way
as to guarantee exclusive write-access and to avoid the
possibility of a message being overwritten before it is read.
One way to do this sort of thing is to have two semaphores for
each message buffer.  One semaphore is called newMessage[], and
the other is called doneReading[].  When a reader wants to read,
he WAITs on newMessage[], reads, and then SIGNALs on
doneReading[].  When a process wants to send a message, she WAITs
on doneReading[], writes the message in the buffer, and SIGNALs
on newMessage[].

All critical section problems you encounter must be solved in
such a way that the mutual exclusion, progress, and bounded
waiting conditions are all guaranteed.  All synchronizations done
must guarantee freedom from all forms of indefinite postponement.

Your program must reflect the inherent parallelism of
heapification.  In other words, everything that *can* go on in
parallel must be *allowed* to go on in parallel.  Your program
must not "force" tasks to proceed serially if they do not need,
for correctness, to proceed serially.

The overall task of the program will be to

1.  read in a list of 31 numbers from standard input (see sample.in),

2.  to create an array containing the numbers, in the order read, 

3.  to transform the array into a heap using the parallel heapify algorithm, 

4.  to write some lines of output while doing the heapifying of step 3, and 

5.  to write the finished heap to the standard output in a specific format.  

Here is the way the heap is written when the input is that of
file sample.in:


                              717
              569                             695
      541             200             650             489
  499     465     051     078     501     602     198     069
076 328 040 012 032 030 043 011 082 072 173 067 004 049 019 059


Write the program so that this part of the output is performed by
just one thread.  The root thread or the mother thread (if
different from the root) is a logical choice for assignment to
this job.

Assume that the numbers in the input are all integers between 0
and 999 (inclusive).

During the heapification process, threads will be doing swaps and
communicating to each other.  (I discussed ways of communicating
above.)  I want you to program each thread so that it writes a
line to standard output each time it does a swap, and each time
it, in effect sends a message to another thread.  In the case of
a swap, the line of output must identify which thread is doing
the swapping, and the identities of the threads whose values are
being swapped.  In the case of a message, the line of output must
indicate the identity of the sender, the identity of the
recipient, and the nature of the message.  Use integers in the
range 1..31 (not 0..30) to identify the threads in these lines of
output.  In this numbering scheme, the children of node number i
are nodes numbered 2i and 2i+1.  Here are some sample messages:



Node04 tells Node02: Tree(Node04) is a heap now. Node07 tells Node03: Tree(Node07) is a heap now. Node05 tells Node02: Tree(Node05) is a heap now. Node02 swaps values with Node05. Node02 tells Node05: Please Reheap Tree(Node05). Node05 swaps values with Node11. Node06 tells Node03: Tree(Node06) is a heap now. Node05 tells Node11: Please Reheap Tree(Node11). You are free to create your own phrasing of the lines that the threads write to standard output. Whatever you do, work it out so that it is very clear. From reading this output, I want to be able to easily tell what happens during the execution of the program, and to get a true impression of the actual order in which events occur. Aim to program the "right" amount of feedback from the threads. It is possible to have too much, and it is also possible to have too little, so use good judgement. Of course, the threads will have to lock standard output while they write their lines of output. ################################################################# Figure out a protocol by which the job indicated can be done. We will have some class discussions to help facilitate this design stage. Once you have decided on the protocol, write it down in pseudo-code form and e-mail it to me by the first due date. This design should be in the form of two or more procedure listings, showing what the threads and the mother process will be doing while the program is running. By the second due date, send a complete, compilable, source listing with adequate comments (The bottom line on the question of documentation is that I need to be able to read your program!) Also, in a separate e-mail message, send a copy of your test script(s). As in the first assignment, do what you can to test for time-dependent errors. Send only the main program, heapify.cpp. I will compile it on a Sun Ultra with my own copies of sem.h and sem.cpp. For this assignment, you may again work in teams of two (2) people. If you work in a team, make sure that both names are in your comments.

Here is the list of things you have to turn in:

  1. On the first due date e-mail a psuedo-code description of the algorithm for your solution. Use this subject line: CS3750,prog2,pcode

  2. On the second due date e-mail a shar file containing:


    Use this subject line: CS3750,prog2,final.

Note that there are no spaces in the subject lines given. It is important that you do not insert any spaces. My e-mail address is: john@ishi.csustan.edu.


DUE DATES:

For due dates, see the class schedule.