April 19, 2019
For today:
1) Read Think OS Chapter 10 and do the reading quiz
2) Finish Homework 10 (Exercise 12)
3) Work on your project
4) Prepare for a quiz
Today:
1) Quiz
2) Producer-consumer problem
3) Condition variables
For next time:
1) Read Head First C Chapter 11
2) Start Homework 11
3) Submit a project update (rough draft of final report)
Use case: work queue, a common pattern for co-operating threads.
Common implementation: circular buffer (which has the pro and con of being fixed size)
By the way, this is a good data structure to know about: https://en.wikipedia.org/wiki/Circular_buffer
The consumer should block when empty. And if the buffer is fixed size, the producer has to block when full.
Coke machine example
Suppose we have a coke machine with space for 3 cans.
One thread is a customer who wants to buy a can.
One thread is a producer who wants to put cans in the machine.
If the machine is empty, the customer has to wait.
If the machine is full, the producer has to wait.
Access to machine operations (take a can, put a can) should be exclusive.
Run the thread simulator:
cd LittleBookOfSemaphores/code
python Sync.py sync_code/coke.py
For a gradual development of this solution, see LBoS Section 4.1.
Think OS Chapter 10 shows how to solve it the POSIX way!
1) Protect access to the queue with a mutex
2) Use a condition variable to signal that the queue is non-empty.
3) Use a condition variable to signal that the queue is non-full.
Two reasons to read this chapter:
1) Transition to more real-world implementation of synchronization.
2) One more example of OO patterns in C.
queue.h is like a Java interface.
queue.c, queue_mutex.c and queue_cond.c are implementations.
1) In ExercisesInC/examples/queue, you'll find the code from Chapter 10. Read queue.c, queue.h, and queue_test.c. Then compile and run queue_test.
cd ExercisesInC/examples/queue
make queue_test
./queue_test
2) Read Makefile and main.c, then compile and run queue:
make queue
./queue
3) Read queue_mutex.c, then compile and run queue_mutex:
make queue_mutex
./queue_mutex
4) Read queue_cond.c, then compile and run queue_cond:
make queue_cond
./queue_cond
5) Modify queue_cond.c so the producer blocks if the queue is full.