OS代写|CPSC 457 – Principle Of Operating Systems Assignment 2


A process is meant to achieve a specific purpose. Different processes achieve different pur
poses. However, it is oftentimes the case that two or more processes need to share, or
exchange data, in order to perform their required duties; this is what is called Interprocess
communication. Your assignment is to make use of the interprocess communication tech
niques discussed in class in order to simulate a busy day at the restaurant.

There are two ways processes can communicate with each other: either by sharing data or by
sending messages. This assignment will require you to share data between multiple processes.

One of the most famous and essential problems in interprocess communication via shared
memory is the producer-consumer problem, also called the bounded-buffer problem. In such
a problem, we have two processes: one called the producer and the other the consumer,
and additionally, there is a bounded buffer in shared memory that both the producer and
consumer write to and read from. The producer is in charge of adding items to the bounded
buffer, and the consumer is in charge of removing them. If the buffer is full, the producer
waits until a consumer takes something. If the bounded buffer is empty, the consumer waits
until the producer adds something.

In this assignment, we will implement an extension to the producer-consumer problem: the
multiple-producer multiple-consumer problem. It is identical to the consumer-producer prob
lem, except as the name implies, multiple processes can produce, and multiple problems can
consume. Also, there may be more than one bounded buffer.

You will solve this problem in the context of a busy day at the restaurant, where you have two
producer processes (chefs), three consumer processes (customers), and two bounded buffers
(food trays).

You are the owner of a locally beloved fine-cuisine restaurant, and your establishment has
been reserved for an upcoming high-profile event. However, the organizers are adamant that
large amounts of food not be prepared in advance, but rather, your chefs should cook fresh
entr´ees and add them to their respective food trays all throughout the duration of the event.

You will thus be in charge of organizing your two specialized chefs (represented by two
producer processes) to constantly resupply two trays of entr´ees (represented by two bounded
buffers), for three queues of hungry customers to take from (represented by three consumer
processes). Each chef specializes in 2 entr´ees, and they strictly add items only to their
respective tray (buffer):

1. Donatello specializes in non-vegan dishes:

(a) Fettuccine Chicken Alfredo
(b) Garlic Sirloin Steak

2. Portecelli specializes in vegan dishes:

(a) Pistachio Pesto Pasta
(b) Avocado Fruit Salad

A chef should randomly pick between either of their specialized entr´ees, and add it to the
entr´ee tray at a random rate between 1 and 5 seconds (inclusive).

The three consumer processes are each programmed as an infinite loop() of customers:

1. The first process will represent customers that want any non-vegan dish.
2. The second process will represent customers that want any vegan dish.
3. The third process will represent customers that want one of each.

A customer needs to wait if there’s not enough of any of their desired dishes. The chefs
need to wait if any of their respective trays are full. After a customer takes an item, the
respective customer process should wait 10-15 seconds (inclusive) before iterating again.

Before beginning part one, you need to understand how to create child processes, how to
share data between them, and how to synchronize them such that there are no race conditions
between them, which occur when two or more processes want to alter the shared data at the
same time. In particular, we need to have an understanding of the following functionalities:

1. Creation of multiple child processes using fork(), and the ability to run specific func
tionality on each child process

2. Data sharing using mmap(), so that we can share the bounded-buffers and the
semaphores between the processes

3. The utilization of POSIX semaphores as a tool for process synchronization.

Once we have an adequate understanding of all the previous functionalities, we are able to
start on the assignment. The following steps should help you organize your work on the

Before any child processes are created, we need to create the two shared bounded-buffers:
one for the tray of non-vegan entr´ees, and one for the tray of vegan entr´ees. We are using
POSIX for this assignment so you should be using mmap() for your shared data.

The bounded-buffers themselves should be of type int; a value of 0 means this slot in the
entr´ee tray is unoccupied, 1 means it has food type one (Fettuccine Chicken Alfredo for the
non-vegan buffer, Pistachio Pesto Pasta for the vegan buffer), and 2 means it has food type

2 (Garlic Sirloin Steak for the non-vegan tray, Avocado Fruit Salad for the vegan tray). Give
these buffers a size of MAX BUFFER SIZE, which is a constant equal to 10.

At this point, you should be able to fork(), and if your shared buffers were created with
the appropriate flags, then both child and parent should be able to read and write from this
buffer. Test it before continuing!

Next up, for each bounded-buffer, we need a shared binary semaphore that makes sure
only one process can write to the buffer at any one time. Call this semaphore mutex as it
is acting as a lock for the buffer. For each buffer, we will also need two shared counting
semaphores – called full and empty – that ensure a producer can’t go into its critical sec
tion if the buffer is full, and likewise, a consumer can’t do so if their respective buffer is empty.