CSE 532S Lock Free Data Structures 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 upload a file with your answers to the assignment page for this studio in Canvas.

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. Create a new empty directory for this studio (for example named something like lock_free).

    In that directory, edit a new C++ source code file (which should be named something like lock_free.cpp) and in it write a main function whose signature looks like the standard (i.e., portable between Linux and Windows) shell (on Windows, terminal window) program main function entry point for C++: int main (int, char * []). Please also use the #define precompiler directive to define a manifest constant whose value is 0, and have the main function simply return that constant to indicate successful completion of the program.

    Implement the basic lock free stack shown in Listing 7.2 of [Williams], declare an instance of it parameterized with int in your main function, call its push method a few times with different integer values, and then have main return 0 to indicate success. Build and run your program (note that you may need to add the -latomic flag when you compile), and as the answer to this exercise please explain why the push method's while loop does not need to repeat the statement just before it that loaded the value of the atomic head pointer into the new node's next pointer (i.e, why does it only contain an invocation of the compare_exchange_weak method?).

  3. Update your code from the previous exercise to implement the (leaky) stack implementation given in Listing 7.3 of [Williams], including updating the node struct, adding the pop method, etc. In your main function, call different sequences of push and pop and print out the values that were pushed and popped when you did that. Build and run your program, and confirm that all values pushed were subsequently popped once the stack became empty again. As the answer to this exercise please show your code and the output your program produced.

  4. Update your main function from the previous exercise so that it spawns two threads, one of which pushes an ascending sequence of odd numbers (1 then 3 then 5 etc.) onto the stack and then pops off as many numbers as it pushed, and stores them in a distinct container that is accessible to main. The second thread should do the same thing, but with an ascending sequence of even numbers (0 then 2 then 4 etc.) and also with its own distinct container into which it stores the values it pops. The main function should then join with both of the threads, and print out the values that are in each of the containers.

    Build and run your program and as the answer to this exercise please indicate whether you saw evidence of the threads' pushes and pops interleaving in interesting ways. For example, did either of the containers end up with both even and odd numbers? Please describe what you saw and what it means for how the threads accesses to the lock free stack were interleaved.

  5. Implement the final version of the lock free stack with reference counting and relaxed atomic operations shown in Listing 7.13 of [Williams] and repeat the previous exercise with it.

    Build and run your program, and as the answer to this exercise describe whether you saw any differences in the program's behavior compared to in the previous exercise, and if so what they were.

    Enrichment Exercises (Optional)

  6. Modify your code from the previous exercise so that instead of using relaxed atomic operations it uses strict sequentially constistent operations.

    Build and run your program, and as the answer to this exercise describe whether you saw any differences in the program's behavior compared to in the previous exercise, and why you think there were or were not.

  7. Implement some or all of the lock free queue features shown in the subsequent listings in [Williams] Chapter 7, and run similar trials with it as you did with the lock free stack in the previous exercises.

    Build and run your program and as the answer to this exercise describe what you implemented and what results you saw (and any interesting behaviors you noticed) when you did that.

  8. Try out any of the previous exercises on another machine, in another compiler, etc. (e.g., in Visual Studio 2019 on Windows). As the answer to this exercise, please describe the platform and compiler you used, whether you noticed any differences in program behavior on it vs. on the windows lab machines, and why you think there were (or were not) any differences.