Please complete the required studio exercises listed below, along with any of the (optional) enrichment exercises that interest you.
As you work through the exercises, please record your answers in a file, and upon completion please e-mail your answers to the firstname.lastname@example.org course e-mail account with Active Object Studio in the subject line.
Please make sure that the name of each person who worked on these exercises is listed in the first answer, and that you number your answers so they are easy for us to match up with the appropriate exercise.
Copy over your source and header files for the
synchronized_list class template from
the previous studio into the directory where the new project expects to find them, and add them to
the project. Please make sure you make separate copies
of the files in the directory where Visual Studio 2013 expects to find source and header files
from the project, rather than attempting to add the original Monitor Object studio's files into
the Active Object studio's project - not only will you make it easier for Visual Studio 2013 to
find things where it expects them (and thus avoid some errors that can crop up otherwise), but
you also will have a version of your code that you can look back at (and possibly revert back to)
even as you're making changes to the version that you're updating in this studio.
In the main C++ source code file for the project (which should be named something like
active_object.cpp) please modify the main function signature so that it
looks like the standard (i.e., portable between Windows and Linux) main function entry point
int main (int, char * )
In a separate header (and possibly source) file, declare and define an
class template parameterized with a data type parameter
T, which has a
of T as a private member variable, a public default constructor (that default constructs the member variable),
enqueue method that
takes a T and calls its
synchronized_list member variable's
and a public
run_service method that calls the
synchronized_list member variable's
pop_back method, prints out the value it obtained from that call to the standard output stream,
and then returns.
In your main function, declare an instance of your
active_object class template (on the stack)
int, and try calling its
methods in different orders (some of which may deadlock and some of which may not, due to the synchronization
synchronized_list member variable) and with different integer values.
Build and run your program with those methods called in different orders, and as the answer to this exercise, please describe under which conditions the program deadlocked and under which it did not.
run_servicemethod private, and modify it so that while the flag member variable is true (if not the method should simply return) it repeatedly (1) calls the
pop_backmethod, and (2) prints out the value it obtained from that call, to the standard output stream.
Add a public
activate method that checks whether or not the object is already active and if it is not
constructs a (local)
std::thread object with a pointer to the
run_service method and
a pointer to the current object, and then detaches the thread. For this studio we'll rely on the main
function to call the
activate (and later the
method only once for each active object, though in practice (and optionally as an enrichment exercise today) you
should also ensure it is thread safe but doesn't diminish concurrency unnecessarily.
Modify your main program so that instead of calling the
run_service method it calls the
activate method, calls the
enqueue method repeatedly, sleeps for a sufficient
interval (so that the enqueued values all can be popped and printed out), and then returns.
Please make sure to add any additional synchronization that is needed, but please also
think about whether or not the synchronizaton within the
synchronized_list is adequate.
Build and run your program, and as the answer to this exercise please describe how the program's behavior changed, compared to its behavior in the previous exercise.
synchronized_listso that it has a flag to determine whether or not it has been shut down, and update the synchronization logic so that if it has been shut down a thread that would have waited for its condition to become true now simply returns from the method it is in. Add a
shut_downmethod that (1) acquires the lock, (2) sets that flag (3) and then calls
notify_all(to wake up all waiting threads) before releasing the lock and returning.
Add a public
deactivate method to your
active object that checks whether or not
the object is already active and if it is sets the flag member variable to false and then calls the
shut_down method of the
synchronized_list, before returning.
In your main function, try repeatedly activating, using, and deactivating the same active object, with suitable sleep intervals to allow the active object to complete its work (in practice, and optionally as an enrichment exercise in today's studio, you would use promises and futures or some other explicit coordination mechanism to ensure a reliable ordering of initiation and completion events across multiple threads). Build and run your program, and as the answer to this exercise please describe the program's behavior in each variation you tried.
active objectclass template so that it optionally takes a pointer to another object of the same type (defaulted to 0 if no pointer is passed) and stores it in a private member variable (which you should also add).
Also modify your
run_service method so that if the pointer is zero it prints out each value
as before, but if the pointer is non-zero it instead enqueues the value in the active object to which it is
pointing (unless there is a cycle of pointers among objects, one of them is at the end of the chain and
eventually prints out the values).
In your main function, default construct one active object, and then construct another active object with its address (please also feel free to try chains longer than 2, if you'd like), and enqueue a number of values into the second active object (but not into the first one, since the second one will pass them all to it).
Build and run your program and as the answer to this exercise (1) show the output your program produced, and (2) describe any differences you saw in how the program behaved in this exercise, compared to in the previous ones.
deactivatemethods of one or more active objects, from the main thread and/or other threads. See if you are able to discover any races or other concurrency hazards involving them, or if not please think about whether any might be possible. Modify the definitions of those methods to avoid those hazards, and as the answer to this exercise please describe what you observed and how you modified those methods.