Makefile
: one for a program that runs Director
,
Player
, and Play
functionality concurrently
as in lab 2 (we'll call this program the Director
program),
and another one for a Producer
program that interacts
with the user and with various Director
programs that
have registered with it;
Producer
program, declare and define a Producer
class
that (1) can interact with the user (through the standard input and standard
output streams in the terminal window where it is running) to display
status and receive commands, and (2) also can interact (via sockets) with the
Director
object in each of one or more running
Director
program processes, to coordinate the initiation and
termination of one or more plays at once on one or more host computers;
Producer
program that can initialize a
Producer
object, create and register appropriate event handlers,
and run a reactive event loop to handle any signals,
exceptions, or other events that may occur;
Director
's program, all of which the Director
should pre-process in order to
size its thread pool accordingly;
Director
and
Producer
programs so that even while
other activities are in progress the event handlers they register can
send, receive, and process information across multiple sockets, iostreams,
etc. from within a reactive event loop running within a single thread;
Director
and
Producer
programs, so that if the user hits Ctrl-C
the signal is caught and the program can then initiate an
appropriate termination protocol, including performing necessary
actions in order to notify other programs, release resources,
and shut down gracefully.
If you are working in a different team for this lab than in a previous lab, you are allowed to reuse code from any of your earlier lab solutions, though if you do that you should please add comments acknowledging contributions from anyone who is not on your current team (and noting in which previous lab their contributions were made), to the code you submit.
Make separate copies of the (source and header) code files
from lab 2 that you are using for this assignment, and put them into
the directory for the lab 3 Director
program. This can make it easier (1) to ensure you have all
the files when packaging up your solution to submit it, and (2) to
revert to a previously stable code base if a change you
are trying doesn't pan out well.
In this assignment, you will again work with input files in similar formats as in the previous lab 2 assignment, but instead of working with a single script, multiple script files should be able to be specified and used.
For example, a program might be given two script files, partial_hamlet_act_ii_script.txt and partial_macbeth_act_i_script.txt for the first parts of Act II from William Shakespeare's "Hamlet, Prince of Denmark" and Act I from William Shakespeare's "Macbeth" respectively (text obtained from the Literature Page web site at http://www.literaturepage.com/read/shakespeare_hamlet.html), with corresponding configuration files hamlet_ii_1a_config.txt, hamlet_ii_1b_config.txt, and hamlet_ii_2a_config.txt for the first script file and macbeth_i_1_config.txt, macbeth_i_2a_config.txt, and macbeth_i_2b_config.txt for the second.
As in the previous labs, each scene fragment's configuration file gives the name of each character in the scene fragment along with their corresponding part file, e.g., Polonius_hamlet_ii_1a.txt and Reynaldo_hamlet_ii_1a.txt in hamlet_ii_1a_config.txt, Polonius_hamlet_ii_1b.txt and Ophelia_hamlet_ii_1b.txt in hamlet_ii_1b_config.txt, King_hamlet_ii_2a.txt and Queen_hamlet_ii_2a.txt and Rosencrantz_hamlet_ii_2a.txt and Guildenstern_hamlet_ii_2a.txt in hamlet_ii_2a_config.txt, FIRST_WITCH_macbeth_i_1.txt and SECOND_WITCH_macbeth_i_1.txt and THIRD_WITCH_macbeth_i_1.txt and ALL_macbeth_i_1.txt in macbeth_i_1_config.txt, MALCOLM_macbeth_i_2a.txt and DUNCAN_macbeth_i_2a.txt and SOLDIER_macbeth_i_2a.txt in macbeth_i_2a_config.txt, and LENNOX_macbeth_i_2b.txt and MALCOLM_macbeth_i_2b.txt and DUNCAN_macbeth_i_2b.txt and ROSS_macbeth_i_2b.txt in macbeth_i_2b_config.txt.
To complete this assignment please perform the following tasks:
Director
program (starting with your lab 2
solution) as follows, to support multiple plays:
argv[1]
and argv[2]
) as the port and IP
address (respectively) at which it
should connect to a Producer
object,
(3) treats the third command line argument (argv[3]
)
as the minimum number of threads that the program should use in
its thread pool, and (4) treats each command line argument after
that as the name of a script file that it should load, parse, and use.If an incorrect number of command line arguments is given, the program should print out a helpful usage message as in:
cout << "usage: " << argv[0] <<
"<port> <ip_address> <min_threads> <script_file>+" << endl;
Director
program
should parse all of the script files and their configuration files to
determine the maximum number of character parts that appears in any
consecutive pair of scene fragments in any of the plays in the list:
as in lab 2 the Director
should then take the maximum of
that value and the value from the third command
line argument, and create that many Players
.
Director
program should first connect a socket to a Producer
program,
using the port and ip address given in the first and second command line
arguments, and then wait reactively for further commands from the
Producer
, according to the instructions below.
Producer
program as follows:
Producer
class that can
(concurrently and/or
reactively) (1) interact with the user
via the cin
and cout
standard input and
output streams; (2) listen for and accept (on a port whose number
is either a default value or one that is provided to its constructor)
socket connection requests from Director
objects running
in other threads or processes; and (3) interact with those
Director
objects over the socket connections.
The Producer
should present the user with a numbered
menu of the plays that are available from the Director
objects connected to it, and a status indicator for each play that
says whether the play is available to be performed,
unavailable (due to its director being in the midst of
performing a different play) or in progress. The Producer
should refresh that list whenever a play is started, completes, or is
stopped by the user, or a Director
object connects or disconnects.
The Producer
should accept and dispatch commands from
the user, which are of the form
<action> [<number>]
where the recognized
actions are quit
(which should terminate the
Producer
program), start
followed by the number
for a currently available play (which tells the appropriate director
to start performing that play), or stop
followed by the number
for a play that is currently in progress (which tells
the appropriate director to stop that play).
argv[0]
) and if more parameters are provided simply issues a helpful usage message
like the following before returning a unique non-zero error code for that case:
cout << "usage: " << argv[0] << "[port]" << endl;
Otherwise the main function should construct a Producer
object, register appropriate handlers, and run a reactive
event loop until the program is terminated by the user.
Director
program so that it uses a port number value (either the one provided to
it on the command line, or a default one if no argument was provided) and IP address (either the one provided to
it on the command line or a default one if necessary)
to establish a socket connection to a running Producer
program.
After identifying its list of plays, the Director
should send that list over the socket to the
Producer
, and then should wait for a command to start a play, and upon receiving a command to start
of the plays it currently has available should start that play and then notify the Producer
that
the play has started.
Similarly, once the play completes, the Director
should notify
the Producer
that the play has finished (and that the
Director
is now available to perform another play or that
one again).
Please ensure that your Director
program performs its
interactions with the Producer
and all other event handling
(e.g., for signals as is described below) in a reactive event loop,
using handlers to interleave read, write, and signal handling operations
at fine granularity even while a play is being performed.
Producer
that the play should be stopped, by
issuing a command of the form stop
followed by the numer of a
play that is currently in progress. The Producer
should
notify the Director
immediately that the play should be
stopped.
The Director
should listen reactively for stop commands from
the Producer
even while a play is in progress, and upon
receipt of a stop command should immediately communicate that to the
Player
threads which in turn should stop performing the
play, release resources and reset information
as appropriate, and return to a quiescent state in which they are ready
to start another play if asked to do so.
For example, you may want to have the Director
set a stop flag
in the Play
object, which
the threads then can detect, and also have the
Director
notify any threads that may be waiting on a
condition variable, as in the thread interruption examples from the
course text book (and our studio exercises based on that chapter).
Once all of the threads have stopped and are reset and quiescent, the
Director
should then immediately
notify the Producer
that the play has stopped, and the
Producer
should refresh its menu of
options to indicate to the user that the play (and any others that
were unavabilable while it was in progress) is now
available to be performed.
Director
process, the process should
catch and handle that signal as follows. The event
handler that receives the signal could simply mark a flag
indicating that the program has been interrrupted, which
one or more of the threads in the program should check
reasonably frequently. Alternatively, you could structure your
code so that the event handler stops the reactor's event loop and closes
the reactor - as in exercises for the Acceptor/Connector studio. How you
realize this behavior is up to you, and you should please document your
design and the thinking behind it in your lab report.
Once shut-down is begun, the stopping protocol described above should be
performed, the Director
should tell the Producer
that it is shutting down, and then all threads should release resources
and terminate, and the program should end gracefully.
When notified of the director's shut-down, the producer should simply
remove the plays from that Director
from its list, and
should then update the menu it shows to the user, accordingly.
quit
command to the
Producer
, the Producer
should send a
termination message to each Director
that is registered with
it, wait for the acknowledgement from each Director
, and
then have each of its threads release resources and terminate, after
which the Producer
program should end gracefully.
Each Director
should listen reactively for termination messages,
and upon receipt of a termination message should perform the shut-down
protocol described above (as though it was being shut down because of
a Ctrl-C signal).
Producer
process, a signal handler should initiate
(or set a flag that causes another object or thread to initiate)
the termination protocol described above (as
though it was being shut down because of a quit
command).
Please make sure to test your program with different combinations of plays running and available, and generating various start, stop, and termination events under those different conditions. Please make sure that your solution does not freeze up (deadlock) or suffer obvious (i.e., more than a second or two) delays in its operation or in the handling of events, 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. Please also make sure that when a play is stopped the various objects involved with it are reset into a state where they can re-start that same play, perform another play, etc.
One approach to this would be to have each Player
sort their
structured line data by number (thus also trivially solving the issue of
lines being scrambled in the part definition file), and then inform the
Director
of all the contiguous ranges of their line numbers.
The Director
then could match up all the ranges
from all the Player
s, identify any gaps in the line
numbers, and then implement a protocol such that when a gap is reached the
Director
simply advances the current line counter to the start
of the next range that some Player
is ready to recite.
How you design this is up to you, though you should please test your solution thoroughly to ensure that whether or not line numbers are missing, misordered, and/or duplicated the program performs correctly in all other features as well as in the ones for extra credit. Please make sure to document your design decisions, and your rationale for them, as well as describing how you implemented this extra credit portion, in your project report under a section that is clearly identified as being for the extra credit portion.
Alternatively, (for up to an extra 5 percent of the assignment's value) instead of the centralized approach described above (which may be a bit more straightforward to design), develop a distributed approach to detecting and handling missing lines, e.g., based on timeouts, barrier synchronization, and possible a signaling protocol among the players in a play. This may require each player to record information about its progress, the progress of other players, and then may require each player to use timed waits in combination with recording that information, to avoid deadlock.
However you design your approach, please provide both a detailed explanation of your implementation, and a rationale for how it avoids deadlock and delivers all the lines that are available, in your project report.
The first section of your ReadMe.txt file should include:
The second section of your ReadMe.txt file should provide detailed instructions for how to:
.zip
(or .tar.gz
) file containing:Makefile
for building your Director
and Producer
programs,
#pragma once
// body of the header file
#if ! defined (MY_FILE_H)
#define MY_FILE_H
// body of the header file
#endif /* defined MY_FILE_H */
new (nothrow)
)
new
) and/or
write exception safe code (e.g., using the RAII idiom) - please don't let an exception escape main uncaught, though.
#define
macros