Lab 8: Synchronization

The goal of this lab is to practice using locks and semaphores to protect access to critical sections. You will use a lock in a few places in relation to a nested loop to observe the timing that results from different granularities of locking. You will also use a pair of semaphores to control the timing back and forth between two threads.


Preliminaries

Set up a bare repository on stu.cs.jmu.edu based on the instructions in the CS 361 Submission Procedures, using the name lab8-synch.git.


Implementation requirements: Protecting critical sections

For this first part, your goal is to protect a critical section created by a nested loop. The inner-most loop adds 1 to a shared variable then subtracts 1 from it. The end result should be 0 if this critical section is protected. Your task is to use a lock as needed. You will also need to set up two threads to run concurrently and perform this calculation.

  1. Edit the run() function in mutex.c to create then join two threads, each of which run the runner() function from the same file.
  2. Use the lock to synchronize access to the shared variable in runner(). The base distribution uses a NULL pointer for shared. You need to change this to get the reference from the thread arguments. Note that you can place the locking and unlocking function calls in multiple places. One of the unit tests includes a timing constraint that you must pass: Correct placement of the lock will result in parallel execution that is at least three times as fast as the sequential execution, but no more than six times as fast.

Due to the unpredictable nature of threads and the workload on stu, it is possible that the timing tests might fail occasionally. If you run it again without recompiling and it passes, then that is fine.


For the second part, you will use two semaphores to control the timing of two threads to produce "PING!" and "PONG!" messages back and forth several times. For a correct implementation, these messages should alternate every line; there should never be multiple lines in a row of the same message. The semaphores can ensure this happens.

  1. Edit the ping() function in pingpong.c to create and initialize the semaphores. You will need to determine the initial values. This thread should then create the pong() thread, passing references to both semaphores, then enter a loop to alternate messages. Complete the rest of the code based on the embedded comments.
  2. Next, implement the pong() thread based on the comments. This code should be very similar to the loop in the pong() function.

In the final implementation of this lab, the "PING! message should always appear first. After the alternating messages, the "PONG: Game over" message should appear before the "PING: Game over" message. The timing of this last alternation arises by having the parent thread join the child.

For completeness, be sure to clean up the semaphores with sem_close().



James Madison University logo


© 2011-2024 Michael S. Kirkpatrick.
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.