CSE 532S Synchronization Studio

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 cse532@seas.wustl.edu course e-mail account with Synchronization 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.


    Required Exercises

  1. As the answer to the first exercise, list the names of the people who worked together on this studio.

  2. Open up Visual Studio 2013, make sure your settings are for C++, and create a new project for this studio (for example named something like synchronization).

    In the main C++ source code file for the project (which should be named something like synchronization.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 for C++: int main (int, char * [])

    Declare an define a class that has a vector of int as a private member variable, and the following public methods:

    • A public insertion operator (operator<<) that takes a reference to a const int and pushes it back onto the vector member variable, and then returns a reference to the object on which the method was invoked (e.g., return *this;)

    • A public function call operator (operator()) that takes no arguments and returns the sum of all the int values in the vector member variable (or 0 if there are none).

    In your main function, declare an instance of the class (on the stack) and write a number of statement using each of the operators to insert some int values into the object, obtain and print out the sum of the values in the object, insert some more values into the object, print out that sum, and so on (for at least a few repetitions of that sequence).

    Build your program and run it from a windows terminal shell (hint: you can run cmd from the main start window to get a terminal shell) and confirm that the sums that are printed out each time are correct. As the answer to this exercise, please show the code you wrote and the output your program produced.

  3. Modify your code so that instead of all being run sequentially in the main function, the different statements are run in different C++11 threads. At least separate multiple different sequences of insertions and multiple different sequences to obtain and print the sums into separate threads.

    Build and run your program and as the answer to this exercise (1) show the code that runs the sequences in the different threads, (2) show the output your program produced, and (3) describe any differences you saw in how the program behaved in this exercise, compared to in the previous one.

  4. Modify your code to add a private std::mutex member variable to the class, and a declaration of a local std::lock_guard<std::mutex> variable as the very first line of each of the class method, which is initialized with the std::mutex member variable. Also add a synchronized print method (you can overload for multiple types if you'd like) that the threads can use to synchronize their use of the standard output stream.

    Build and run your program and as the answer to this exercise (1) show the modified class declaration and definition code, (2) show the output your program produced, and (3) describe any differences you saw in how the program behaved in this exercise, compared to in the previous one.

  5. Add a method to the class called factorial_of_sum that takes no parameters and (1) declares a local std::lock_guard<std::mutex> variable initialized with the std::mutex member variable (as the very first line of each of the class method, so that the insertion operator cannot change the set of values over which it is operating as it is doing so); (2) calls the function call operator method to obtain the sum of the values in the vector member variable; and (3) computes and returns the factorial of the value returned by the function call operator.

    Modify your code so that at some point in its execution (and before at least some other calls to class methods that it makes) each of the threads calls the factorial_of_sum method and prints out the result.

    Build and run your program, and as the answer to this exercise describe what happened when the threads did that.

  6. Convert your class into a class template, parameterized with the type of lock that is used (i.e., the type of the private member variable, the type with which the lock guards are instantiated, etc.). Instantiate the previous class (now class template) object with std::recursive_mutex (instead of std::mutex which would make the code behave as in the previous example - please feel free to try out that variation as well, if you'd like).

    Build and run your program, and as the answer to this exercise (1) show your modified code, and (2) describe how the program's behavior differed compared to the previous exercise.

    Enrichment Exercises (Optional)

  7. Modify the design and implementation of your class according to the Thread Safe Interface pattern by moving all code that is shared between two different methods (for example the code to traverse the vector and return the sum of the values in it) into an unsynchronized private method that the synchronized public methods then call.

    Build and run your program, and as the answer to this exercise please show your modified code and the output your program produced.

  8. Extend your class with:

    • a private static pointer to a global instance of the class, which is initialized to 0;

    • a private static member variable of type std::once_flag;

    • a private static initialization method that checks whether or not the private static pointer is 0 and if it is allocates a new instance of the class and stores its address in the pointer; and

    • a public static instance() method that takes no parameters, uses the std::once_flag member variable and the std::call_once function to call the private static initialization method (the call is then actually dispatched exactly once, at the beginning), and then returns the private static instance pointer.

    Modify your main function so that instead of declaring and using an instance of the class on the stack, it always uses and accesses the global (singleton) instance of the class (hint: the syntax you'll want is something like classname::instance()->).

    Build and run your program, and as the answer to this exercise please show your modified code and the output your program produced.