John Sarraille
THE HANDOUT!
CS 3750 -- Operating Systems I
Statement of the "PROTOCOL"
Concurrent Programming Problem
User0 User1
| \ / |
| \ / |
| \/ |
| /\ |
| / \ |
| / \ |
Buffer0 Buffer1
| \ / |
| \ / |
| \/ |
| /\ |
| / \ |
| / \ |
Agent0 Agent1
Write a C program that uses four threads in one task to
simulate the situation depicted in the diagram above. There
must be two USER threads and two AGENT threads.
USER threads run an infinite loop. In each iteration of the
loop, a USER randomly chooses Buffer0 or Buffer1, increments a
private serial number, and copies a "packet" into the chosen
buffer. The packet contains the id number of the USER (0 or 1)
and the current serial number. (This is simulates a pair of
processess or threads sending what might be long messages by
placing them in a "mailbox." To keep the programming simpler,
we do not actually write long messages.)
AGENTS also run an infinite loop, continually examining both
buffers. The AGENTS cooperate to copy out each packet that has
been copied in by a USER. (This simulates two threads sharing
a kernel task that takes messages out of a sender's mailbox and
delivers them to the intended recipient's mailbox.
Alternatively, you can think of this set-up as a form of
producer consumer problem, where there are two producers, two
buffers, and two consumers.
You may find it is convenient to use one or more flags in each
buffer. Threads may read and write flags in order to
communicate. (However you will need to use semaphores for some
of the communication/synchronization actions.)
Your program must carefully prevent concurrent threads from
corrupting the contents of shared variables. For example, it
is an error if a USER overwrites a part of a packet that has
not yet been copied out by an AGENT. On the other hand, a
thread must never unnecessarily prevent another thread from
accessing a buffer.
To enforce exclusive access to shared buffers, you must use
semaphores implemented by sem.h and sem.c. The exact manner in
which you employ the semaphores is for you to decide.
USERS must write a specific output when they place a packet in
a buffer. Example:
Copy IN: Packet #0 of USER #1 into buffer #0
This line of output must be written in such a way that it is
guaranteed to appear on the screen BEFORE an AGENT prints a
message saying it has copied this packet out of the buffer.
AGENTS have to cooperate to make sure that only one AGENT
copies out each packet. Each AGENT can and will copy packets
out of either buffer, competing with the other AGENT to copy
out as many packets as possible as soon as possible. If either
AGENT stops copying packets, the other AGENT must automatically
do all the work, copying all packets from both buffers. If one
AGENT is busy copying a packet from one buffer, and if there is
a packet in the other buffer that needs to be copied, then the
other AGENT must immediately begin copying from the other
buffer. AGENTS must write a specific output when they copy a
packet from a buffer. Example:
AGENT #1 copies packet #145 of User #0 from buffer #1.
This line of output must be written in such a way that it is
guaranteed to appear on the screen BEFORE a USER prints a
message saying it has placed the next packet in this buffer.
Note: Please format USER and AGENT messages so that the packet,
user, and buffer numbers all line up in columns. This will
make it a lot easier to check outputs.
To test your program, you must insert in critical places code
that delays each thread by a random amount of time. You can do
this by generating a random integer n, and then making the
thread execute
for (i = 0; i < n; i += 1) cthread_yield();