COMP3000 Operating Systems F23: Tutorial 6
In this tutorial you will be learning about two implementations of the producer-consumer problem, a classic example of a concurrency problem. The class textbook covers concurrency in great detail in Chapters 25-34, and the producer-consumer problem is covered in Chapter 30 (Condition Variables) and Chapter 31 (Semaphores). While you can look at this part of the textbook, note that we will not be covering this material in the same level of detail, as should be clear from this tutorial.
A: Getting Started
Download 3000pc.zip, unpack, and run make
to compile 3000pc-fifo
and 3000pc-rendezvous
.
Try to take this opportunity to read and understand the two programs line by line.
- Note that these programs take 3 arguments each:
- The number of events to process
- The number of events to produce before the producer sleeps for 1 second
- The number of events to consume before the consumer sleeps for 1 second
- Note that these programs take 3 arguments each:
- Run both programs with the same arguments of your choice. Do this a few times with different arguments. Do they behave the same way? Do you notice any differences? (again, no “correct” answers but just play with them and document your observations)
- Repeat the above experiment, this time running each program under
strace
(with the-f
flag to trace children too). Do you notice any difference in the system calls each program makes? Remember to ignore the lines beforemain()
that might be distracting, e.g., start looking around and after theclone()
system call. - You can see there is "
#define QUEUESIZE 32
" in both programs. Are they actually used? Why (not)?
B: Producer/Consumer with Pipes
- Examine the source code of
3000pc-fifo
. Pay attention to the call topipe(pipefd)
on line 192 and make the connection with what has been discussed in the lecture (also look at the man page forpipe(2)
). Explain the following:- How does the consumer receive words to consume?
- How does the producer generate and send words to the consumer?
- Why is the call to
srandom(time(NULL))
on line 169 necessary?
- Replace the call to
srandom(time(NULL))
on line 169 withsrandom(42)
. What differences do you notice in3000pc-fifo
's behavior?
- Examine the source code of
3000pc-rendezvous
. Explain the following:- What are a few ways that
3000pc-rendezvous
is different from3000pc-fifo
? - What does the call to
mmap()
on line 347 do (compared to our previous uses ofmmap()
)? How did you figure this out? - How does the producer notify the consumer that the queue is no longer empty?
- How does the consumer notify the producer that the queue is no longer full?
- What are a few ways that
- What arguments can you provide to make the producer wait for the consumer? Hint: Check the size of the queue.
- What arguments can you provide to make the consumer wait for the producer? (You can disregard the wait at the very beginning as the queue is initially empty)
- Another student tells you that the difference between processes and threads is that processes never share memory, while threads do. Is this statement correct or incorrect? How can the behavior of
3000pc-rendezvous
help justify your answer? - Change the calls to
pthread_mutexattr_setpshared()
andpthread_condattr_setpshared()
(lines 293 and 298) to take 0 instead of 1. How does the behavior or3000pc-rendezvous
change? Does anything break?