These problems should be done on your own. You get credit if you turn in something, and we are not checking the correctness. So these exercises exist purely to reinforce the material, not to evaluate you.
Getting help from AI (besides being ruled out by the course policies) will actually hurt you, since the point of these questions is for you to gain the practice and experience of working through the problems.
You will need that general skill (of absorbing something by practicing it) in life, and in this semester you will need the specific problem-solving skills that are emphasized in these homeworks.
Smokers
Consider a system with three smoker processes and one agent process. Each smoker continuously rolls a cigarette and then smokes it. But to roll and smoke a cigarette, the smoker needs three ingredients: tobacco, paper, and matches. One of the smoker processes has paper, another has tobacco, and the third has matches. The agent has an infinite supply of all three materials.
The agent places two of the ingredients on the table. The smoker who has the remaining ingredient then makes and smokes a cigarette, signaling the agent on completion. The agent then puts out another two of the three ingredients, and the cycle repeats.
Assume the agent calls the procedure
void chooseIngredients(int *paper, int *tobacco, int *match);
to randomly select 2 of the 3 ingredients. The routine randomly sets 2 of the ints to "1" and one of them to "0". You don't have to write this routine.
Write a program to synchronize the agent and smokers:
What synchronization and state variables will you use in this problem? (For each variable, indicate the variable's type, the variable's name, its initial value (if any), and a short comment describing the variable's purpose.)
Variable Name Variable Type Initial Value Description
Write the routines
Agent()
andmatchSmoker()
(the routine for the smoker that has lots of matches). You don't have to write the routinespaperSmoker()
ortobaccoSmoker()
, but your solution should be general enough so that those routines would be simple variations ofmatchSmoker()
.
Auction
In this problem you will simulate a simplified auction, encapsulated in a monitor, Auction
. Your job is to finish the implementation of Auction
. Here is the specification:
Auction
hasNUM_BIDS
slots to hold bids; an auction can happen only when all of these slots are full.There are endless buyer threads, each of which makes a bid by calling the
Auction::RegisterBid()
method. If there are no free slots to hold bids, this method must wait. Otherwise, this method inserts its bid into a free slot (after which the slot is no longer free). After it does so, the method returns; in particular, the method does not wait for the results of the auction.There are one or more auctioneer threads, which each call the
Auction::SelectWinner()
method. This method simulates a single auction. Per the first bullet, this method can proceed only if all slots are occupied. Otherwise, it waits. When it does proceed, it computes the maximum bid from among all candidate bids in theAuction
, clears all of the slots, and returns the maximum bid.You must follow the class’s concurrency commandments.
Don’t wake threads unnecessarily.
Hint: Write helper functions, for example to determine whether there are free slots.
Where indicated, fill in the variables and methods for the Auction
object. Remember to follow the concurrency commandments.
Auction auction; // global
class Auction {
public:
Auction();
~Auction();
void RegisterBid(uint32_t amount);
uint32_t SelectWinner();
private:
uint32_t bids[NUM_BIDS]; // bids[i] == 0 means that slot i is free
// ADD MORE HERE
};
Auction::Auction()
{
memset(bids, 0, sizeof(bids));
// FILL THIS IN
}
void
Auction:RegisterBid(uint32_t amount)
{
// We use 0 to mean "slot free"
assert(amount > 0);
// FILL THIS IN
}
uint32_t
Auction:SelectWinner()
{
// FILL THIS IN
}
Sleeping barber
This is a potentially useful (if convoluted) example to exercise your understanding of how to use mutexes and conditional variables. It is a well-known concurrency problem. The writeup and solution are due to Mike Dahlin (who used to be on the faculty at The University of Texas at Austin). He asked this question on a midterm once.
Work through the problem on your own; we will post the solution next week.
A shop has a barber, a barber chair, and a waiting room with NCHAIRS
chairs. If there are no customers present, the barber sits in the chair and falls asleep. When a customer arrives, the customer wakes the sleeping barber. If an additional customer arrives while the barber is cutting hair, the customer sits in a waiting room chair if one is available. If no chairs are available, the customer leaves the shop. When the barber finishes cutting a customer’s hair, the barber tells the customer to leave; then, if there are any customers in the waiting room, the barber announces that the next customer can sit down. Customers in the waiting room get their hair cut in FIFO order.
The barber shop can be modeled as 2 shared objects:
A
BarberChair
, with the methodsnapInChair()
,wakeBarber()
,sitInChair()
,cutHair()
, andtellCustomerDone()
. The BarberChair must have a state variable with the following states:EMPTY
,BARBER_IN_CHAIR
,LONG_HAIR_CUSTOMER_IN_CHAIR
,SHORT_HAIR_CUSTOMER_IN_CHAIR
.Note that neither a customer or barber should sit down until the previous customer is out of the chair (
state == EMPTY
).Note that
cutHair()
must not return until the customer is sitting in the chair (LONG_HAIR_CUSTOMER_IN_CHAIR
).Note that a customer should not get out of the chair (that is, return from
sitInChair()
) until the customer’s hair is cut (SHORT_HAIR_CUSTOMER_IN_CHAIR
).The barber should get in the chair (
BARBER_IN_CHAIR
) only if no customers are waiting.You may need additional state variables.
A
WaitingRoom
, with the methodsenter()
andcallNextCustomer()
.enter()
returnsWR_FULL
if the waiting room is full or (immediately or eventually) returnsMY_TURN
when it is the caller’s turn to get their hair cutcallNextCustomer()
returnsWR_BUSY
orWR_EMPTY
depending on if there is a customer in the waiting room or not. Customers are served in FIFO order.
Thus, each customer thread executes the code:
Customer(WaitingRoom *wr, BarberChair *bc)
{
status = wr->enter();
if (status == WR_FULL) {
return;
}
bc->wakeBarber();
bc->sitInChair(); // Wait for chair to be EMPTY
// Make state LONG_HAIR_CUSTOMER_IN_CHAIR
// Wait until SHORT_HAIR_CUSTOMER_IN_CHAIR
// then make chair EMPTY and return
return;
}
The barber thread executes the code:
Barber(WaitingRoom *wr, BarberChair *bc)
{
while (1) { // A barber’s work is never done
status = wr->callNextCustomer();
if (status == WR_EMPTY) {
bc->napInChair(); // Set state to BARBER_IN_CHAIR; return with state EMPTY
}
bc->cutHair(); // Block until LONG_HAIR_CUSTOMER_IN_CHAIR;
// Return with SHORT_HAIR_CUSTOMER_IN_CHAIR
bc->tellCustomerDone(); // Return when EMPTY
}
}
Write the code for the WaitingRoom
class and the BarberChair
class. Use locks and condition variables for synchronization. Follow the coding standards specified in Mike Dahlin’s Coding Standards for Threads Programming, which you will also follow in Lab 3.
Hints (and requirement reminders):
remember to start by asking for each method “when can a thread wait?” and writing down a synchronization variable for each such situation.
List the member variables of class
WaitingRoom
including their type, their name, and their initial value. Then write the methods forWaitingRoom
.List the member variables of class
BarberChair
including their type, their name, and their initial value. Then write the methods forBarberChair
.
Handing in the homework
Use Gradescope; you can enroll in our course with entry code 7XNDBJ.