(Last revision 10/27/99)

10/27/99: Revised the due dates.

CS 3750 First C Programming Assignment (prog #1)


Due Thursday, October 28 -- psuedo-code description of the algorithm for your solution.

Due Tuesday, November 09 (in two separate e-mail messages -- please no "enclosures" or attachments.") -- the completed program source code in one e-mail message -- one or more script(s) documenting thoughtful, adequate, intelligent testing

1. Look over the contents of the directory "ThreadInfo" in our web space. Read the file HiHo.c in that directory. It illustrates everything you need to know about using function calls from the C threads package on the NeXT's, and about using the queuing semaphores implemented by the sem.c and sem.h files. Make copies of sem.c and sem.h for your own use. (We will go over this in class.)

2. Use the queuing semaphores to implement a "cheerleader pyramid" program that spawns 10 cheerleaders (threads), assigns each of them a position in the pyramid, and causes them each to execute a C function which writes a message to standard output when they take their position in the pyramid.

Just as a real pyramid must be built from the ground up, so must be the pyramid created by the threads in your program. The threads will have serial numbers 1, 2, 3, 4, 5, 6, 7, 8, 9, and 10. The pyramid they are trying to build looks like this:
      01
    02  03
  04  05  06
07  08  09  10
Thread #1 cannot join the pyramid until threads #2 and #3 are in position. Thread #2 cannot join until threads #4 and #5 are in position. Similarly, #3 must comes after #5 and #6, #4 after #7 and #8, #5 after #8 and #9, and #6 after #9 and #10.

It will be the job of your program to synchronize the activities of the threads and to see to it that the messages the threads write come out in an order consistent with the constraints above.

The synchronization that accomplishes the above must be done by employing the semaphore data types implemented by the files sem.c and sem.h. You don't get credit if you don't use semaphores to do this.

In *addition* to the constraints mentioned above, imposed by the shape of the pyramid, there is also a need to enforce mutually exclusive access to standard output. The constraints above are not enough to guarantee that (say) thread #4 will not try to write its message concurrently with #6. This could cause output from #4 and #6 to be written to the screen in a jumbled interleaving.

We want the message of each thread to be written atomically, on its own separate line of the output. This is really a separate problem. I will solve this one for you by telling you exactly what to do. Let's cover that topic in class, since there are some details I don't want to go into here.

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.

The program must be written so that there is a "mother" task which creates the 10 cheerleader threads. The cheerleaders must notify the mother after they have finished their message, and then exit. The mother must make sure that all the cheerleaders have finished with their messages before she exits.

3. Figure out a protocol that allows the mother and threads to cooperate to do the job indicated above. 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 and understand your program!) Also, in a separate e-mail message, send a copy of your test script(s).

(Beware: since some errors in concurrent programs are timing-dependent, you will need to think of some novel ways to test your program. The file HiHo.c illustrates this. Ask for more details in class.) All you have to send me is the main module, pyramid.c, and I will compile it on a NeXT with my own copies of sem.h and sem.c, so it will work for me if it worked for you. For this assignment, you may work in teams of two (2) people. If you work in a team, make sure that both names are in your comments!

More Discussion of the Assignment

When you think about doing this assignment, imagine that the mother thread and each cheerleader thread will run on a separate CPU of a tightly-coupled multiprocessor. Of course, our NeXT computing systems are not tightly-coupled multiprocessors. Nevertheless, the point of this exercise is for you to write a program that will work on *any* computing system on which multiple processes can execute concurrently while sharing variables.

A tightly-coupled multiprocessing system can be diagrammed this way:
  CPU     CPU     CPU      CPU     CPU     CPU   CPU    MEMORY
    |       |       |        |       |       |     |    |
 ------------------------------------------------------------ BUS
       |      |       |     |     |     |     |     |     |
     CPU    CPU     CPU   CPU   CPU   CPU   CPU   CPU   CPU
Here we have a RAM memory being shared over a common bus by several CPU's. It is possible that the different CPU's have radically different speeds. Speed can be affected by the inherent power of the CPU, or by the current load on the CPU. Besides that, it is impossible to tell which CPU will be assigned to which thread. And also, each time we run the program, the assignment can be different.

In your program, the mother process must create all the cheerleaders without delay immediately after the program starts running. The mother must do nothing to direct the creation of the pyramid. In general it is a bad idea to create "traffic cop" threads, because the traffic cop too often becomes a bottleneck. When every action has to be approved by a master, events can only happen as fast as the master can approve them. This would defeat the purpose of parallel processing.

The only interactions a cheerleader is allowed to have with its mother, after its creation, is that each cheerleader will somehow notify the mother after it has positioned itself in the pyramid and written its message to standard output. This is done so that the mother can know when to exit.

The cheerleaders must cooperate among themselves, using semaphores for synchronization, to create the pyramid. As to the decision of when a cheerleader X moves into position, only X and the cheerleaders that will be supporting X are allowed to participate in the making of that decision.