Lab 2: Threads & Semaphores
Operating Systems
Due: Wednesday, March 3, 1:00 PM

(VIP students have 2 weeks from when you receive it.)

We are using the Nachos educational software which is intended to provide basic OS functionality that may be extended to enable students to develop and implement OS components. This handout describes how to set up your software environment, which files you need to read and understand for this assignment, the lab 2 assignment, how to turn in this assignment (as well as others), some programming tips, and sample output for this assignment.

Getting Started

  1. The Nachos software runs only on the DecStation machines in the EdLab. The machine names are: delux1 through delux9, and deluxa through deluxj. You should do all your compiling, testing, and executing on these machines. For information on dialing in remotely to an EdLab machine, see the EdLab web page.

  2. The first step in doing the assignments is to make a copy of the following directory in your course directory, ~/cs377, as follows:
    cd ~/cs377
    cp -r /courses/cs300/cs377/cs377/nachos/nachos-3.4 .
    
    If you next type ls, you should see: nachos-3.4, which contains Nachos source code for each assignment. You will not need the directory nachos-3.4/doc, and you can delete it from your account if you wish (using rm -r -f nachos-3.4/doc.

    Now change directory to your nachos-3.4/code directory (using cd nachos-3.4/code and type make all to compile the nachos software and place an executable called nachos in each of the subdirectories. If you have trouble compiling, i.e., the compilation terminates with an error, please get in touch with the TA, but we do not expect this to happen.

    For the assignments you should NEVER need to modify the machine directory.

  3. Then you can start doing your assignment. To enable us to find your changes to the source code, you should surround every piece of code you modify with:
    // start changes
       put your changes here
    // end changes
    
  4. Late Policy: Assignments are due at 1:00pm on the due date. Projects will be accepted up to 4 days after the due date with a 10% penalty for each day it is submitted late. No project will be accepted after this 4 day period. We will check the time stamp on your files in your directory to ascertain the time you completed your assignment. For full credit, do not modify the files after the time mentioned in the assignment handout.

Understanding the Nachos software

In this assignment, we give you part of a working thread system; your job is to complete it, and then to use it to solve two synchronization problems.

Here are some pointers to overviews of the thread and synchronization mechanisms in Nachos (these are hot links if you read this on the Web):

After installing the software, your first step is to read and understand the partial thread system we have written for you. This thread system implements thread fork, thread completion, along with semaphores for synchronization. Run the program nachos in the threads directory for a simple test of our code. Trace the execution path (by hand) for the simple test case we provide. (The main program for threads/nachos is in threads/main.cc. It has been compiled with THREADS defined, but USER_PROGRAM, FILESYS, and NETWORK undefined.)

When you trace the execution path, it is helpful to keep track of the state of each thread and which procedures are on each thread's execution stack. You will notice that when one thread calls SWITCH, another thread starts running, and the first thing the new thread does is to return from SWITCH. We realize this comment will seem cryptic to you at this point, but you will understand threads once you understand why the SWITCH that gets called is different from the SWITCH that returns. (Note: because gdb does not understand threads, you will get bizarre results if you try to trace in gdb across a call to SWITCH.)

The files you need to make sure you understand completely for this assignment are listed below. You can view them over the Web.

main.cc, threadtest.cc (in the threads directory)
a simple test of our thread routines.

synch.h, synch.cc (in the threads directory)
synchronization routines: semaphores, locks, and condition variables.

In addition, you need to use (but not modify) parts of some other files:
interrupt.h (in the machine directory)
manage enabling and disabling interrupts as part of the machine emulation.

list.h (in the threads directory)
generic list management.

scheduler.h (in the threads directory)
manages the list of threads that are ready to run. You will need to use the ReadyToRun method to indicate that a thread is ready to run.

system.h (in the threads directory)
Nachos startup/shutdown routines. You will need to use the variable currentThread to identify the thread currently running.

thread.h (in the threads directory)
thread data structures and thread operations such as thread fork, thread sleep and thread finish.

Properly synchronized code should work no matter what order the scheduler chooses to run the threads on the ready list. In other words, we should be able to put a call to Thread::Yield (causing the scheduler to choose another thread to run) anywhere in your code where interrupts are enabled without changing the correctness of your code. You will be asked to write properly synchronized code as part of the later assignments, so understanding how to do this is crucial to being able to do the project.

To help you test your programs, the code linked in with Nachos will cause Thread::Yield to be called on your behalf in a repeatable but unpredictable way. Nachos code is repeatable in that if you call it repeatedly with the same arguments, it will do exactly the same thing each time. However, if you invoke ``nachos -rs #'', with a different number each time, calls to Thread::Yield will be inserted at different places in the code.

Make sure to run various test cases against your solutions to these problems; for instance, for part one, create multiple producers and consumers and demonstrate that the output can vary, within certain boundaries.

Warning: in our implementation of threads, each thread is assigned a small, fixed-size execution stack. This limitation may cause bizarre problems (such as segmentation faults at strange lines of code) if you declare large data structures to be automatic variables (e.g., ``int buf[1000];''). You will probably not notice this during the semester, but if you do, you may change the size of the stack by modifying the StackSize defined in switch.h.

Although the solutions can be written as normal C routines, you will find organizing your code to be easier if you structure your code as C++ classes. Also, there should be no busy-waiting in any of your solutions to this assignment.

The Assignment

For this assignment and all subsequent ones, you may work in groups of 1 or 2.
  1. (15 points). Implement locks. We have provided the public interface to locks in synch.h. You need to define the private data and implement the interface. Note that it should not take you very much code to implement locks. You should only need to modify synch.h and synch.cc. You should not need to modify the public parts of synch.h. (Hint: You may find semaphores and primitive thread routines useful as building blocks. Look at the Salsa tutorial for additional hints.)

  2. (35 points). Implement producer/consumer communication through a bounded buffer, using semaphores and/or locks. (A solution to the bounded buffer problem is described in Silberschatz, Peterson and Galvin, using semaphores.)

    The producer places characters from a text file named producer_input.txt into the buffer one character at a time; it must wait if the buffer is full. When the producer puts a character to the buffer it should produce the following output to the screen:

      producer <id> producing <character read>
    
    where <id> is the unique identifier of the producer and <character read> is the character just read from the file.

    The consumer pulls characters out of the buffer one at a time; it must wait if the buffer is empty. When the consumer removes a character from the buffer it should produce the following output on the screen:

      consumer <id> consuming <character>
    
    where <id> is the unique identifier of the consumer and <character> is the character just removed from the buffer.

    Test your solution with a multi-character buffer and with multiple producers and consumers. Of course, with multiple producers or consumers, the output will illustrate the concurrency provided by threads.

    Your code should prompt for the size of the buffer, the number of producers, and the number of consumers, in that order. You can assume that a valid integer is provided by the user for each of these. You should be sure that your code works for different input files as we may test it with files other than what you provide.

    The skeleton code to get you started is in /courses/cs300/cs377/cs377/public_html/labs/producer.cc.

  3. (15 points).Condition variables. Implement condition variables. We have provided the public interface to condition variables in synch.h. You need to define the private data and implement the interface. Note that it should not take you very much code to implement condition variables. You should only need to modify synch.h and synch.cc. You should not need to modify the public parts of synch.h.

  4. (35 points). The Sleeping-Barber Problem. Implement a solution to the following problem using locks and condition variables. A barber shop consists of a waiting room with n chairs, the barber chair, and a barber. If there are no customers to be served, the barber outputs "Barber going to sleep." and goes to sleep in the barber chair. If a customer enters the barber shop and all chairs are occupied, then the customer leaves the shop and outputs "Customer <id> leaves without a haircut." If the barber is busy, but chairs are available, the customer sits in one of the free chairs and outputs "Customer <id> is waiting." If the barber is asleep, the customer wakes up the barber and outputs "Customer <id> is waking up the barber." Whenever the barber cuts someone's hair, the barber outputs "Barber cutting hair."

    You should prompt for the number of chairs and the total number of customers that should arrive, in that order. Again, you can assume a valid integer is provided by the user. The skeleton code to get you started is in /courses/cs300/cs377/cs377/public_html/labs/barber.cc.

How to Turn in Lab 2

All of the following files and hard copies must be turned in to get full credit for a question.
  1. Create a directory in your course directory called ~/cs377/lab2. Make the directory group writable (chmod g+w ~/cs377/lab2). Put the following files in this directory.

    For part 1 and 3: synch.h, synch.cc
    For part 2: producer.cc, producer_input.txt, producer
    For part 4: barber.cc, barber
    README

    To create your solutions for parts 2 and 4, do the following in the threads directory:

  2. Hand in a hard copy of all the files that you modified.

  3. Hand in a hard copy of a README file identifying your lab partner (if you have one) and containing an outline of what you did for the assignment. It should also explain and motivate your design choices. Keep it short and to the point. Your ~/cs377/lab2 directory should also contain this file.

    If your implementation does not work, you should also document the problems in the README, preferably with your explanation of why it does not work and how you would solve it if you had more time. Of course, you should also comment your code. We can't give you credit for something we don't understand!

  4. Hand in a hard copy showing sample output from your programs.

  5. Individual Group Assessment (for students working in groups only)
    10 percent of your lab grade will come from your participation in this project as a member of your two person group.
    What you need to turn in (each person individually):
    Turn in a hard copy of your assessment of the division of labor in the group in the format shown below.  If you give yourself a 50% and your partner gives you a 50%, you will get the whole 10 points.  If you give your partner a 40% and your partner gives himself or herself a 40%, he or she will get 8 points.  And so on...
    Work Distribution
    My Name:  Crystal Gross 60%
    My Partner:  Kathryn McKinley 40%

Tips

Sample Output


> producer -rs 23232
Please enter the buffer size:  5
Please enter the number of producers:  2
Please enter the number of consumers:  4
producer 0 producing a
producer 0 producing b
producer 0 producing c
producer 1 producing d
consumer 0 consuming a
consumer 0 consuming b
producer 0 producing e
producer 0 producing f
producer 1 producing g
consumer 0 consuming c
consumer 0 consuming d
consumer 1 consuming e
consumer 1 consuming f
consumer 1 consuming g
producer 0 producing h
producer 1 producing i
producer 1 producing j
consumer 0 consuming h
consumer 0 consuming i
consumer 1 consuming j
producer 0 producing k
producer 1 producing l
producer 1 producing m
producer 1 producing n
consumer 0 consuming k
consumer 0 consuming l
producer 0 producing o
producer 0 producing p
consumer 0 consuming m
consumer 0 consuming n
consumer 0 consuming o
consumer 1 consuming p
No threads ready or runnable, and no pending interrupts.
Assuming the program completed.
Machine halting!

Ticks: total 1695, idle 35, system 1660, user 0
Disk I/O: reads 0, writes 0
Console I/O: reads 0, writes 0
Paging: faults 0
Network I/O: packets received 0, sent 0

Cleaning up...

---------------------------------------------------------


> barber -rs 3
Please enter the number of customer chairs:  5
Please enter the total number of customers:  10
Barber going to sleep.
customer 2 is waking up the barber
customer 3 is waiting for the barber
customer 4 is waiting for the barber
customer 5 is waiting for the barber
customer 7 is waiting for the barber
customer 8 is waiting for the barber
customer 9 is leaving without a haircut
customer 10 is leaving without a haircut
customer 1 is leaving without a haircut
Barber cutting hair.
Barber cutting hair.
Barber cutting hair.
Barber cutting hair.
Barber cutting hair.
Barber cutting hair.
Barber going to sleep.
customer 6 is waking up the barber
Barber cutting hair.
Barber going to sleep.
No threads ready or runnable, and no pending interrupts.
Assuming the program completed.
Machine halting!

Ticks: total 954, idle 104, system 850, user 0
Disk I/O: reads 0, writes 0
Console I/O: reads 0, writes 0
Paging: faults 0
Network I/O: packets received 0, sent 0

Cleaning up...