Study Notes for Assignment 2 - Operating Systems | CS 4414, Assignments of Operating Systems

Material Type: Assignment; Professor: Son; Class: Operating Systems; Subject: Computer Science; University: University of Virginia; Term: Spring 2008;

Typology: Assignments

Pre 2010

Uploaded on 07/29/2009

koofers-user-103
koofers-user-103 🇺🇸

3

(1)

10 documents

1 / 3

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
CS414: Operating Systems
Spring 2008
Nachos Assignment #2
Due: April 1, 2008
Introduction
In the first Nachos assignment, we gave you part of a working thread system.
Your job now is to complete the thread system and then use it to solve several
synchronization problems. The first step is to read and understand the partial thread
system; you should know how the thread system implements thread fork, thread
completion, and semaphores for synchronization. You can run the program “nachos” and
trace the execution path (by hand). You have already done this for Nachos Assignment 1.
For this assignment, you have to write properly synchronized code for the given
synchronization problems. By properly synchronized code, we mean that your 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. Writing properly synchronized
code is crucial to being able to do this assignment.
To aid you in this, 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 #'”, (rs is for random seed) 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,
in part two, 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 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 have this problem, 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 separate classes. It would make your code
easier to read and debug.
Assignment
1. Thread system completion: Complete the implementation of lock and condition
variables in synch.h and synch.cc. You may either use semaphores as a building block, or
--1-
pf3

Partial preview of the text

Download Study Notes for Assignment 2 - Operating Systems | CS 4414 and more Assignments Operating Systems in PDF only on Docsity!

CS414: Operating Systems

Spring 2008

Nachos Assignment

Due: April 1, 2008

Introduction

In the first Nachos assignment, we gave you part of a working thread system. Your job now is to complete the thread system and then use it to solve several synchronization problems. The first step is to read and understand the partial thread system; you should know how the thread system implements thread fork, thread completion, and semaphores for synchronization. You can run the program “nachos” and trace the execution path (by hand). You have already done this for Nachos Assignment 1. For this assignment, you have to write properly synchronized code for the given synchronization problems. By properly synchronized code, we mean that your 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. Writing properly synchronized code is crucial to being able to do this assignment. To aid you in this, 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 #'”, (rs is for random seed) 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, in part two, 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 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 have this problem, 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 separate classes. It would make your code easier to read and debug.

Assignment

  1. Thread system completion: Complete the implementation of lock and condition variables in synch.h and synch.cc. You may either use semaphores as a building block, or

you may use more primitive thread routines (such as Thread::Sleep). We have provided the public interface to lock and condition variables in synch.h. You need to define the private data and implement the interface. Note that you do not need to do too much of coding to implement either lock or condition variables. When you write the description of your implementation, explain and justify your design.

  1. Basic producer/consumer example: Implement producer/consumer communication through a bounded buffer, using lock and condition variables. The producer places characters from the string ''Hello world'' into the buffer one character at a time; it must wait if the buffer is full. The consumer pulls characters out of the buffer one at a time and prints them to the screen; it must wait if the buffer is empty. Test your solution with a multi-character buffer and with multiple producers and consumers. Of course, with multiple producers or consumers, the output display will be gobbledygook; the point here is to illustrate the concept.
  2. VDOT engineering application: You have been hired by VDOT to synchronize traffic over a narrow light-duty bridge on a public highway. Traffic may only cross the bridge in one direction at a time, and if there are ever more than 3 vehicles on the bridge at one time, it will collapse under their weight. In this system, each car is represented by one thread, which executes the procedure OneVehicle when it arrives at the bridge: OneVehicle(int direc) { ArriveBridge(direc); CrossBridge(direc); ExitBridge(direc); } In the code above, direc is either 0 or 1; it gives the direction in which the vehicle will cross the bridge. (a) Write the procedures ArriveBridge and ExitBridge (the CrossBridge procedure should just print out a debug message), using lock and condition variables. ArriveBridge must not return until it is safe for the car to cross the bridge in the given direction (it must guarantee that there will be no head-on collisions or bridge collapses). ExitBridge is called to indicate that the caller has finished crossing the bridge; ExitBridge should take steps to let additional cars cross the bridge. This is a lightly-traveled rural bridge, so you do not need to guarantee fairness or freedom from starvation. (b) In your solution, if a car arrives while traffic is currently moving in its direction of travel across the bridge, but there is another car already waiting to cross in the opposite direction, will the new arrival cross before the car waiting on the other side, after the car on the other side, or is it impossible to say? Explain briefly.