THE PROBLEM
CS 3750 -- Operating Systems I
Statement of the "Packet Protocol"
Concurrent Programming Problem
User0 User1
| \ / |
| \ / |
| \/ |
| /\ |
| / \ |
| / \ |
Buffer0 Buffer1
| \ / |
| \ / |
| \/ |
| /\ |
| / \ |
| / \ |
Agent0 Agent1
Write a 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 (not shared with the other user), 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 senders' mailboxes 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 associated with each
buffer. User and/or agent threads may read and write flags in
order to communicate. (However, accessing shared flags correctly is a
critical section problem that you may need to solve using semaphores.)
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 the message of an agent appears on
the screen, saying the agent 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 one agent gets all done with the work
associated with copying out a packet and then the agent just stops copying
packets for a long time, the other agent must automatically "take over"
and 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 the message of a user appears on the
screen saying it has placed the next packet in this buffer (the packet with
the next highest number.)
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) sched_yield();