(Latest revision 2017/11/05)
[2017/11/05: Clarified that one team member only sends e-mail]
CS 3750 First C++ Concurrent Programming Assignment
(prog #1)
- Review
the sample programming assignment solution, dmnd.cpp and possibly some of the other documents
in
the sampleAssignment subdirectory of the ThreadInfo subdirectory in the class web space.
This material illustrates what you need to know about using function
calls from the pthreads package on the CS Lab Macs, and about
using the queuing semaphores implemented by the sem.cpp and sem.h
files. Make copies of the versions of sem.cpp and sem.h in this assignment
space for your own use. (Ask any questions you have about this in class.)
- Starting with the skeleton program called sequence.cpp, you must
add code that uses queuing semaphores to ensure that the constraints listed at
the beginning of the program are enforced.
As the comment in the program states, threads 0, 1, and 2 may begin
executing their (simulated) task any time after the mother creates
these threads. Threads 3, 4, and 5 are required to start their tasks
only after certain threads have completed their tasks, as detailed
in the program comment. You need to add code that uses semaphores to ensure
that these timing constraints are enforced.
Each of the child threads also is required to increment a counter.
This is a critical section problem. You need to add code to the
program to solve that critical section problem.
The synchronization that accomplishes the above must be done by
employing the semaphore data types implemented by the files
sem.cpp and sem.h. You don't get ANY credit unless you achieve
the results with semaphores.
Notice that, in addition to the constraints mentioned above, there is
also a need to enforce mutually exclusive access to standard output
(the computer screen). Enforcing the constraints above does not
guarantee that two threads (say threads 3 and 5) will not try to write
their messages to the screen concurrently. This could cause the messages
from the two threads 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 an additional
critical section problem that has to be solved by the program.
However, you don't have to do anything at all about it, because
I put code in the skeleton program that takes care of it.
Solve the problem in a distributed fashion. In other words, if thread
X needs to wait until thread Y is in place, then program thread X and Y
to communicate with each other. Don't try to program a 'third party'
that tells both X and Y what to do and when to do it.
Use semaphores. Keep things simple. Any synchronizations you
program must guarantee freedom from all forms of indefinite
postponement.
You must use only semaphores to make processes
wait for events. In particularly, and importantly, you are not
allowed to use a while-loop that keeps iterating until some condition
becomes true. You are not allowed to use loops like the ones we
studied in Peterson's algorithm, for example. You are also not
allowed to use similar loops that repeatedly wait on a semaphore.
If a thread needs to wait for some event, it should be able to do that
by executing a single wait_sem operation on a sim_semaphore
variable.
If you feel you have to program a "wait-loop," you are
thinking about the program in the wrong way, and you should
get some help from me and figure out a different approach.
The program has a "mother" task that
creates the six child threads, and you must retain that structure.
(Add code only in the manner directed in the comments of the skeleton
program.) The group of children must somehow notify the mother thread after
all the children have completed their (simulated) tasks.
The mother has to make sure all the children have finished
with their messages before the mother exits.
- 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. You should send me a copy of the
sequence.cpp skeleton program with your pseudo code inserted
in the appropriate places - where the "real code" will go
later.
By the second due date, send a complete, compilable, listing
of sequence.cpp 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, place copies of test scripts
in a separate file, and e-mail that to me too.
(Remember: I don't accept attachments to e-mails. So don't
send me any of those. Send a shell archive as inline text
- more about how to do that further on.)
(Beware: since some errors in concurrent programs are
timing-dependent, you will need to think of some novel ways to
test your program. The sample assignment solution and the skeleton version of
sequence.cpp have code that illustrates this idea. If you want, you can ask
questions in class to work on more ideas.)
Please do not send me copies of sem.h or sem.cpp.
I have those. I will use my copies to compile with your program for testing.
Double Please: Do not send me copies of your compiled code.
I don't want it and it will snarl up my e-mail.
Just send me your source code, only the main module: sequence.cpp
I will compile it on a CS Lab Mac with my own Makefile and copies of sem.h,
sem.cpp. Your program should work for me if it worked for you.
For this assignment, you may work in teams
of two (2) people, but you don't have to if you don't want to.
If you work in a team, make sure that both names are in your comments!
If you don't understand something, ask me questions. Don't expect "magic
enlightenment." :-)
More Discussion of the Assignment
When you think about doing this assignment, imagine that the
mother thread and each child thread can run on a separate
CPU of a tightly-coupled multiprocessor. The program may or may
not actually use multiple cores or CPUs. 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 CPUs. It is possible that the different CPUs have
radically different effective 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 of threads to CPUs can be different.
In your program, the mother process creates all the
children without delay, immediately after the program starts
running. (Don't change that!) After creating them, the mother
must do nothing to direct the actions of the children.
In general it is a bad idea to create "traffic cop" threads that "direct
traffic", because the traffic cop too often becomes a bottleneck.
When every action has to be approved by a controlling process, events
can only happen as fast as the boss can approve them.
This would often defeat the purpose of parallel processing.
I gave you a good skeleton program. Just add code in the places indicated,
so that the program starts working correctly. Don't rewrite the program
in other ways.
The only interactions ANY child is allowed to have with its
mother, after its creation, is that a child is allowed to
notify the mother after it has completed its task
and written its message to standard output.
The children must cooperate among themselves, using
semaphores for synchronization, to perform their tasks in
a correct order. As to the decision of when a child X performs its task,
only X and the children that are required to precede X are allowed to
participate in the making of that decision.
The general rules for submitting assignments by e-mail are:
- One person only from each team sends the e-mail.
The names of both team members must appear in a comment at
the beginning of the source code file.
- Always send me e-mails as plain text in the main message
body. Never send me attachments.
- When you send a program source file, you also send
a script
of your tests. Combine the source file and the script
into one
shell archive (shar) file.
- I will tell you what subject line to use with each
message, and I need you to use exactly the
subject lines I give you. (I get hundreds of e-mail
messages at a time and your subject line allows me to
sort messages.)
- Send each submission before midnight on the due date.
Here is the list of things you have to turn in:
- On the first due date e-mail a
pseudo-code description of the algorithm for your
solution (in-line in a copy of the skeleton program).
["Pseudo-code" is not a synonym for "vague and/or incomprehensible"
:-). It means you describe specifically exactly what the code
you are going to insert will do, in a step-by-step, algorithmic
fashion, but you are not required to obey the syntax of the C++ programming
language. You just write the steps in clear English.]
Use this subject line for the e-mail of the pseudo-code:
CS3750Prog1Pcode
- On the second due date e-mail a
shar file containing:
- the completed program source code (the sequence.cpp file only)
- one or more script(s) documenting thoughtful,
adequate, intelligent testing
Use this subject line: CS3750Prog1Final
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.