CSE 532 Fall 2015
Lab 0: "All the platform's a stage, and all the threads merely players"
Points: 5% of final grade
Submitted: by electronic submission to email@example.com
Due: by 11:59pm Tuesday September 15, 2015
The purpose of this assignment is to give you experience with multi-threaded
programming and basic synchronization techniques, using C++11 threading and synchronization features.
We will use wrapper facades from the C++11 libraries, and the design,
implementation, testing, and debugging skills you'll develop using them,
repeatedly throughout the semester.
In this assignment you will work in groups of 1, 2, or 3 people (but not more) to
write a C++11 program (in Visual Studio 2013) that can:
You will start by writing a simple program in which the main thread of execution will:
- launch multiple threads that read individual parts of a fragment of a play
from separate input files;
- synchronize the transfer of lines from those parts into a common script; and
- sort the lines and print out the order in which they would be given in the play.
- read a configuration file giving the the name of the play (or fragment of a play) and the
names of the characters and the files where their parts are defined;
- construct a Play object through which lines of the play will be stored, sorted, and printed out;
- launch threads that each will (asynchronously) read their part from their individual files
and insert them into the Play obect;
- join with each of the threads; and then
- print out a properly ordered script for the entire fragment of the play.
Throughout this assignment, you will work with input files in particular formats (which
different parts of the program you are writing will use as described above).
For example, based on a portion of William Shakespeare's "Hamlet,
Prince of Denmark", ACT II, Scene II, "A room in the Castle." (text
obtained from the Literature Page web site at
http://www.literaturepage.com/read/shakespeare_hamlet-31.html) the script fragment hamlet_act_ii_scene_2.txt can be represented by the
configuration file hamlet_ii_2_config.txt and the corresponding part files
To complete this assignment please perform the following tasks:
- Write a Play class (you are free to use additional classes if you'd like) with the following members:
- a string for the name of the play (or play fragment);
- a container of structured lines from the play (feel free to declare a struct for this if you'd like, though you could
also use the standard
pair or other construct to do this) which include
(1) a number reflecting the order in which the line is given in the play,
(2) the name of the character by which the line is given, and (3) the text of the line itself;
- a constructor that takes the name of the play as an argument and uses it to initialize the string member variable
(the container member variable should start out empty, and should be populated dynamically by the insertion operator);
- an insertion operator (
operator<<) that will take a
structured line as an argument and add it to the member
container, and then return a reference to the Play object on which the operator was invoked; and
print method with a void return type that takes a reference to an
ostream, and uses the
ostream and the structured lines
stored in its member container to print out a properly ordered script in a format similar to that found in the
hamlet_act_ii_scene_2.txt script fragment.
To ensure that the lines are printed out in the correct order, the Play class either should use an
associative container that keeps them in order as they are inserted into it, or should sort the container
as the first action of the
To ensure that lines are associated with the proper characters, as it goes the Play class
print method should keep track of which character is currently speaking,
and when a change occurs print out (1) a blank line and (2) a line with the name of the new character
(with a period at the end) before printing out the new character's subsequent lines.
Play class will be used by multiple concurrent threads, please make sure to
synchronize access so that data races and other race conditions are avoided, e.g., by applying the Scoped
Locking and/or Thread Safe Interface patterns that we discussed and worked with in the studios.
- Write a simple function (which different threads will all run) that takes a reference to a (non-const) Play object, a reference to a const
C++ style string (the character's name), and a reference to a (non-const) input file stream object
(for a character part file formatted like Queen.txt),
and repeatedly (until it reaches the end of the input file stream):
- reads a line from the input file stream;
- converts the first whitespace delimited token of the line into a number (e.g., an unsigned int);
- stores the rest of the line in a C++ style string; and
- if (and only if) both the number and some non-whitespace text were extracted from the line, inserts
a structured line (based on the number, the character's name, and the text of the line following the number)
into the Play object using its insertion operator.
It is possible that a thread may encounter lines that are badly formed, e.g., with only blank space
or with only a single whitespace deleimited token, and if so the thread should simply skip that line without
issuing an error message, throwing an exception, or otherwise indicating an error, and proceed to the next line.
It is possible that a thread may see no well formed lines, which also is a reasonable case
(e.g., to allow silent characters to enter and leave a scene in later labs) as long as
it does recognize well formed lines if there are any.
- Write a main function (with the standard portable main function signature we specified in the studios) that:
- Uses its first command line argument (
argv) to identify a configuration file formatted like
and reads one line at a time from it (ignoring any lines that only contain whitespace), storing important
information that it will use in the rest of its operation.
If it is run without a configuration file name your program should print out a useful syntax message
(before ending gracefully by returning a unique non-zero error code), like the following:
cout << "usage: " << argv << "<configuration_file_name>" << endl;
Otherwise, the program should store the file's first non-blank line in its entirety in a C++ style string,
as the name of the play, and should treat each non-blank line after that as the definition of
a character's part that will be run in a separate thread.
If a badly formed character part definition line is detected the program should generate an
appropriate error message, skip the line, and continue looking for well formed ones.
A well formed line will contain at least two whitespace delimited tokens (the program should ignore
any additional tokens on a line after the first two), both of which should be stored in C++ style strings.
The first string should be used as the name of the character, and the second should be used as the name
of a valid input text file that contains the character's lines - the program should test whether or not
the file exists and can be opened correctly for reading - if not the program should emit an appropriate
error message, consider the character definition line badly formed, and continue to the next line.
If the configuration file cannot be opened or does not contain at least one valid character definition (including
the proper opening of that character's input file), the program should generate an error message and return a unique
non-zero error code for the kind of failure it experienced.
Otherwise, the main function should:
- construct a
Play object using the name of the play;
- construct a
std::thread object for each well formed character definition line
the program saw, passing its constructor the thread function, a reference to the
a reference to the C++ style string for the character's name, and a reference to the input file stream object
for that character part's input text file of lines;
- join with each of the threads (make sure you do this in an exception safe way so that no join can be missed);
- call the
print method; and
- return 0 to indicate success.
- To test your program, you should please run at least several runs of it with different combinations
of configuration and part files, and make sure that it finishes (no deadlock), that you don't see any
output corruption or program crashes (which may indicate the presence of race conditions), and that
the output generated is correct.
You are strongly encouraged to complete the extra credit portion of the assignment, which in
addition to earning you points directly can make it easier to generate (and then evaluate)
different test cases from existing sources for plays (e.g., on the web).
For up to an extra 5 percent of the assignment's value (scores of up to 105 are possible) write a separate program that can
take (1) the name of
a script fragment file (in the format illustrated by the hamlet_act_ii_scene_2.txt
script fragment file) to process, (2) the name of a configuration file to generate, and (3) the name of the play (given in the remaining command line arguments); and can output an appropriate
configuration file (for example like hamlet_ii_2_config.txt) and the part files
corresponding to the configuration file and the ordering of lines in the script fragment file
King.txt, Queen.txt, and Rosencrantz.txt).
Submit your solution to the extra credit part in a separate .zip file (clearly named to indicate it's the extra credit part)
that you should attach along with the other parts of the assignment to the e-mail you send when submitting your solution.
Also write up your approach to the extra credit part, give instructions for how to unpack, build, and use it, and document
how you used it in your testing of the assignment, in the main ReadMe.txt file for your assignment (instead of creating
a separate ReadMe.txt file for the extra credit part).
What to Submit
As you work on your program, please write down the design decisions you faced, and describe both the
solutions you chose to address them and the rationale for the choices you made, in the ReadMe.txt text file
that should have been generated by Visual Studio 2013.
The first section of your ReadMe.txt file should include:
- the number of the lab (e.g., "CSE 532 Fall 2015 Lab 0")
- the names and e-mail addresses of all team members
- an overview of how your programs are designed,
- the Wrapper Facades you used or extended and how they helped in your design and code, and
- insights, observations and questions you encountered while completing
The second section of your ReadMe.txt file should provide detailed
instructions for how to:
Important:We must be able to receive your e-mail, and
unpack, build, and run your programs using only the instructions in
your ReadMe.txt file and the Visual Studio 2013 version and other tools available on the
CEC Windows lab machines in Urbauer 218.
- unzip or otherwise unpack your files,
- build your program(s), and
- run your program(s)
on the Urbauer 218 lab machines where we will evaluate your lab solutions.
The third section of your ReadMe.txt file should provide a reasonably detailed description of
how you evaluated your solution, including the kinds of configuration and character part files
you used and their formats (including well formed and badly formed content to test how your
program handled those variations), and any other scenarios that you tested that you consider important.
Please submit by e-mail to
firstname.lastname@example.org with a single
.zip file attached containing:
- your source code and header files,
- any example files you think useful
(for example, the different configuration and character part files you used to test your solution),
- output files from at least one significant test of your programs,
- your ReadMe.txt file.
Please also send in a separate copy of your ReadMe.txt file, with
clear instructions on how your submission file was produced and how to
unpack it using tools available on the CEC lab machines.
IMPORTANT:please make sure that no .exe file is included in any .zip file you send, as the WUSTL e-mail servers will block delivery of email with a .zip attachment that includes a .exe file. Please also make sure to send a .zip file (not a .7z file or other zip format) when you send your solutions.
Please treat this assignment as you would a commercial or research
product that you are shipping to a large group of customers. Please
take the time to test, document, and check your work to make sure all
parts are shipped, are of high quality, and behave resonably under a range of different
operating conditions. Grading will focus both
on the quality of your solution and on the quality of the product
itself, as it arrives at the cse532 account.
To ensure the best possible result (and accordingly the highest
possible grade), please pay attention to the following issues:
Correct Compilation and Operation
Your program must compile and run correctly on the CEC Windows lab machines
using the source files you provide. Please make sure
your program compiles without warnings (and of course without errors), and you might even want to try
running it on different compilers (say also using g++ on shell.cec.wustl.edu or one of the other Linux
servers) and fixing all the warnings for
each. Missing files will be handled with a 5 point deduction (possibly per file) if you need to supply a new file
in order for us to build your solution on the CEC Windows lab machines.
Design decisions are largely yours to make, and as long as the design
is concise, coherent, consistent, and addresses all design forces in the
assignment, you will receive full credit. One key area to consider
is whether each abstraction in your design does a single job, does
that job completely, and collaborates appropriately with other
abstractions. Minor deductions (1-3 points, but please be aware minor
deductions can add up) will be made for abstractions
that are unnecessarily large or have inappropriate inter-dependencies.
Major deductions (5-15 points) will be made for larger problems like
neglecting key requirements of the assignment, code that does not compile or that crashes when it runs, etc.
How you implement your solution is again up to you, and we will take
into account different approaches to implementation. Minor deductions
will be made for things your program gets away with but are not good,
like neglecting to check the return value from a system call or
Wrapper Facade method (i.e., the program may have problems under
special conditions), or calling exit(1) from inside a class method
rather than providing a clean termination path. Major deductions
will be made for problems that produce incorrect or extremely
inefficient behavior of the program. The former kinds of errors
should be eliminated during your coding and code review phases, and
the latter kinds of errors should be eliminated during your testing
phase, which should include running different combinations of configuration
and character part files containing well formed and/or badly formed contents.
Different coding styles will also be accepted, as long as they are
clear, readable, and consistent. Please code clearly with both the
reader of the code and the user of the program in mind. Please use
consistent indentation and placement of braces, and comment your code
thoroughly. Use whitespace liberally - it's free and it makes it a
lot easier to read your code. When grading, we will add tagged
comments to the code indicating areas where we found particular issues
to mention, whether or not points are deducted. Only minor deductions
will be made for each style issue, except in extreme cases.
Please make sure you provide adequate instructions on how to unpack,
build, and run your program. Also, please make sure to document your
solution. Minor or even major deductions will be made for inadequate
explanation of how your solution does what it does, why you made key
design choices, or how the user (or grader) can successfully build and
run your program. Even if how you did something is obvious to you,
please assume it is not obvious to the reader.
Missing files in the delivered software make it difficult or
impossible to evaluate your solution. An automatic deduction of up to 5 points
will be applied for each missing or corrupted file that is submitted
later on request.
Labs recieved within 24 hours after the deadline will be graded with an
automatic 10 point deduction. Labs received more than 24 hours after
but within 48 hours of the deadline will be graded with an automatic
20 point deduction. Labs received after 48 hours from the deadline
will not be graded, except under extenuating circumstances. If you are running late completing the
assignment, please let us know about the trouble as soon as possible (and it may be possible to give you
a brief extension if you request it sufficiently in advance of the deadline),
and please turn in as much as you can before each deadline so we can
give at least some credit for the work you have done.
Grading Issues from Previous Semesters
Please avoid the following practices, which have at least drawn at least comments
(and possibly deductions depending on the extent of the issue) in previous semesters:
Please use the following practices to improve the clarity and quality of your code and documentation:
- using hard coded numbers like 2 or 7 (one possible exception is the constant 0).
- using dynamic allocation when a class member or local variable would do: for example if it's dynamically allocated in
the constructor and only ever
deallocated in the destructor, then there must be some reasonable design force that motivates this approach rather than
using an object directly as a member of the class (which your readme file should of course please explain)
- using the same error message or eror return code or exception for different kinds or causes of failures
- using a pointer/size arithmetic formula without a comment explaining it: in general any non-obvious code should have
a comment giving an intuition of what it does in general terms (and even better explaining why or how it does it that way)
- putting non-inline function or method definitions in a header file
- initializing class members in the constructor body when it is possible to intialize them in the base/member initialization list instead
- initializing class members in the base member initialization list when the failure of that initialization could result
in a bad initial state of the object as a whole, e.g., when
a function whose return value matters (or that could throw an exception) is called in an exception-unsafe manner
- unnecessary format restrictions, e.g., not tolerating blank lines and extra whitespace in a file
- leaving commented-out code fragments in code - remove these or use conditional compilation to bring them in/out
- adding comments for things that are already fairly obvious from the code (e.g., begin and end of a method)
- using exit to end the program in the middle of a class method or any method that could be called from another method
- using fixed length buffers when the lengths of inputs to them are variable or unknown
- unnecessarily cramping symbols or lines together, which impacts readability - use whitespace generously: it's free!
- use precompilation include guards in header files to avoid duplicate inclusion:
#if ! defined (MY_FILE_H)
// body of the header file
#endif /* defined MY_FILE_H */
- check the return value from any call that could return an error code after a failure (e.g.,
new (nothrow) )
- use try/catch blocks around any call that could throw an exception after a failure (e.g.,
write exception safe code (e.g., using the RAII idiom) - please don't let an exception escape main uncaught, though.
- use the constructor's base/member initializer list in preference
to the body of the constructor for member intialization, except
were it is necessary to use the constructor body (please see above)
- using typed constant variables with descriptive names in preference to precompiler
- use consistent and appropriate comments
- discuss design decisions in your ReadMe.txt file
- test your code for its handling of error cases as well as of the "happy path"
- perform "tiger team" testing - take turns trying to find cases that break your program, and then fixing them
- using the (C++ style) string class for variable length character buffers
- using whitespace generously: it's free and it improves readability!