All your work for this assignment will take place within the
threads
directory.
Although you might find it helpful to look
at files outside this directory, you should not make any
changes to files other than those in the threads
directory.
In general, if a source code file has the following message at the
beginning:
In industry, when you are part of a team working on a software project, each member of the team will be responsible for a particular part of the system. Eventually, it will be necessary for all these pieces to work properly together. For this reason, team members are provided with interface specifications that specify in detail how their program is to interact with the rest of the system. A team member cannot make gratuitous changes to the names or arguments of functions because these changes will prevent successful integration of the new code with the rest of the system.
In this course, we (the TA, Graders and I) are going to perform a great deal of the building and testing of your software automatically. We will write our own driver functions which we will link with your code. If you adhere exactly to the specifications, everything should work properly. If not, your code will require manual intervention to test, and the large number of students in the class will probably make this impossible for us.
One other thing that will make manual intervention necessary is if your code produces extraneous printout when it runs. You should therefore see to it that your code, as submitted, should produce no printout other than that originally present in NACHOS, or that specifically indicated in the assignment. In addition, if the assignment specifies that you are to produce printout, your printout must appear exactly as specified. Do not add extraneous newlines, extra characters, or change in any way the format of the messages you are told to produce.
You will probably find it useful to incorporate debugging printout
into your code during development and testing. This is OK, but all
such code should use the NACHOS DEBUG
macro defined in threads/utility.h, so that
debugging printout is not produced unless a suitable command-line flag
is provided. Examples of the use of this macro appear throughout the
NACHOS code.
Every time you modify a NACHOS file, you should surround all of your changes with preprocessor commands that make it easy to compile the code without your changes.
When the ``threads'' version of NACHOS is started, it initially
creates a single thread that begins executing the function
ThreadTest()
in the file threadtest.cc. This function
creates a new thread that calls the function
SimpleThread(1)
, and the original thread calls the
function SimpleThread(0)
. The two threads each execute
the loop in the SimpleThread()
function, in which they
yield control of the CPU back and forth five times.
Modify the function ThreadTest()
to take a single integer
argument n
, so that its prototype becomes:
ThreadTest()
should fork
n
new threads instead of just one.
Test your function on values of n
from zero to four.
You will have to change the file
main.cc
to supply
the required integer argument to ThreadTest()
.
Next, modify function SimpleThread()
to read
exactly as follows:
ThreadTest()
set to 0, 1, 2, 3, and 4.
Analyze and explain the results.
Put your explanation in the file threads/HW1_WRITEUP
.
The file synch.cc contains an
implementation of the semaphore operations
Semaphore::P()
and Semaphore::V()
.
Modify SimpleThread()
by introducing calls to the semaphore
operations, so that accesses to the shared variable are properly synchronized.
Try your synchronized version of SimpleThread()
with the
argument to ThreadTest()
set to 0, 1, 2, 3, and 4.
Verify that your code works by observing that the final value of the shared
variable seen by every thread in each case is always (n+1)*5
.
(If there are 5 threads (n=4), then each thread will see final value 25).
Using the #ifdef
/#endif
preprocessor construct,
bracket your synchronization code so that its compilation is controlled by
the preprocessor symbol HW1_SEMAPHORES
.
That is, if the preprocessor symbol HW1_SEMAPHORES
is defined,
the synchronization code should be included, otherwise the synchronization
code should not be included.
Recompile NACHOS both ways to make sure our "conditionalized" code works
properly.
Lock
operations that are missing from the file
synch.cc.
Locks are used to ensure mutual exclusion between threads.
At any time, a lock is either free, or else it is held
by a thread. At most one thread at a time can hold a lock.
If a thread tries to acquire a lock that is currently being held
by another thread, the requesting thread will block (sleep)
until the thread that holds the lock releases the lock. There are four missing functions you must implement:
Lock::Lock(char* debugName)
:
This constructor function initializes a lock object.
The debugName
argument is a string supplied by the
caller, which should just be stored into the new Lock
structure. Its purpose is simply to help distinguish various instances
of locks in debugging printout.
Lock::~Lock()
:
This function deallocates a lock object, when it is no longer needed.
void Lock::Acquire()
:
This function waits for a lock to become free and then acquires
the lock for the current thread.
void Lock::Release()
:
This function releases a lock that was previously acquired by the
current thread, and wakes up one of the threads
waiting for the lock.
Semaphore
code as a
guide when writing the Lock
code. Locks are very much
like semaphores with initial value 1.
Test your code by replacing the Semaphore
operations you
added to SimpleThread()
by corresponding
Lock
operations, and verifying that the demonstration
still works properly. Conditionalize your code so that its
complication is controlled by the preprocessor symbol
HW1_LOCKS
. (Be sure that you can still compile your code
with HW1_SEMAPHORES
defined to get the semaphore
demonstration.)
Condition
operations that are missing from the file
synch.cc.
Conditions are used to ensure proper synchronization among threads.
The specifications for this primitive appear in the synch.h
module.
There are five missing functions you must implement:
Condition::Condition(char* debugName)
:
This constructor function initializes a condition object.
The debugName
argument is a string supplied by the
caller, which should just be stored into the new Condition
structure. Its purpose is simply to help distinguish various instances
of conditions in debugging printout.
Condition::~Condition()
:
This function deallocates a condition object, when it is no longer needed.
void Condition::Wait(Lock* conditionLock)
:
This function waits for a condition to become free and then acquires
the condition for the current thread.
void Condition::Signal(Lock* conditionLock)
:
This function wakes up one of the threads that is waiting on the condition.
void Condition::Broadcast(Lock* conditionLock)
:
This function wakes up all threads that are waiting for the condition.
Semaphore
and Lock
code as a
guide when writing the Condition
code.
available[NMACHINES]
whose elements
are non-zero if the corresponding machines are available (NMACHINES
is a constant indicating how many machines there are in the laundromat), and a
semaphore nfree
that indicates how many machines are available.
The code to allocate and release machines is as follows:
available
array is initialized to all ones, and nfree
is initialized to NMACHINES.
threads/HW1_WRITEUP
.
HW1_WRITEUP
that explains how you design
the code and how your code works, and how to run any test programs you submit.
Make sure your code works when Nachos yields randomly (using "-rs" option).
You should also indicate what does not work and explain your efforts in order
to get partial credits.Your code must compile and link if you want to receive very much credit. After that, you will receive some points if the test programs you supply work properly. We will then execute your code with our own series of user test programs, which will test the system calls you implemented both singly and in combinations. You will receive points for each of our tests your system can execute correctly.
The turnin procedure is given here. For part of the Nachos program you have modified, you should insert the following lines in your code so TAs can read:
//HW1 Begin of Modification
//HW1 End of Modification