In this lab, we practice using a mutex and a condition variable to make a data structure thread-safe—free of race conditions when multiple threads operate on the same data structure.
queue.c is a usual implementation of FIFO queues by a linked list. We need a mutex so multiple threads operating on the same queue is safe. We also need a condition variable because one function intends to wait until the queue is non-empty. Here is an outline of your job:
Add a mutex and a condition variable in the queue
struct, intended to guard its existing fields. (It would be overkill to
guard every node.)
They need to be the “dynamic” kind because even the queue itself is created at run time. (And an application may create and use multiple independent queues.)
This means in queue_create() you call the appropriate
init functions, and dually in queue_free() you call the
appropriate destroy functions.
Both queue_add() and queue_take() need
to lock and unlock the mutex.
queue_take() needs to use the condition variable to
wait until the queue is non-empty. Dually, queue_add()
needs to signal the condition variable to say “new data added!”.
This lab is simple enough that both
pthread_cond_signal() and
pthread_cond_broadcast() are acceptable.
queue_test.c is a sample tester.
Without your addition for thread safety, it is actually so bad that more than 99% of the time it hangs in the middle!
After your addition, it is true that the order of data that the reader sees is non-deterministic. We won’t worry about it—at least it receives all data successfully!
If you like to print debugging or error messages for your own sake, please send them to stderr only.
Please hand in the amended queue.c.