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();