Main Page   Compound List   File List   Compound Members   File Members  

synch.h

Go to the documentation of this file.
00001 // synch.h 
00002 //      Data structures for synchronizing threads.
00003 //
00004 //      Three kinds of synchronization are defined here: semaphores,
00005 //      locks, and condition variables.  The implementation for
00006 //      semaphores is given; for the latter two, only the procedure
00007 //      interface is given -- they are to be implemented as part of 
00008 //      the first assignment.
00009 //
00010 //      Note that all the synchronization objects take a "name" as
00011 //      part of the initialization.  This is solely for debugging purposes.
00012 //
00013 // Copyright (c) 1992-1993 The Regents of the University of California.
00014 // All rights reserved.  See copyright.h for copyright notice and limitation 
00015 // synch.h -- synchronization primitives.  
00016 
00017 #ifndef SYNCH_H
00018 #define SYNCH_H
00019 
00020 #include "copyright.h"
00021 #include "thread.h"
00022 #include "list.h"
00023 
00024 // The following class defines a "semaphore" whose value is a non-negative
00025 // integer.  The semaphore has only two operations P() and V():
00026 //
00027 //      P() -- waits until value > 0, then decrement
00028 //
00029 //      V() -- increment, waking up a thread waiting in P() if necessary
00030 // 
00031 // Note that the interface does *not* allow a thread to read the value of 
00032 // the semaphore directly -- even if you did read the value, the
00033 // only thing you would know is what the value used to be.  You don't
00034 // know what the value is now, because by the time you get the value
00035 // into a register, a context switch might have occurred,
00036 // and some other thread might have called P or V, so the true value might
00037 // now be different.
00038 
00039 class Semaphore {
00040   public:
00041     Semaphore(char* debugName, int initialValue);       // set initial value
00042     ~Semaphore();                                       // de-allocate semaphore
00043     char* getName() { return name;}                     // debugging assist
00044     
00045     void P();    // these are the only operations on a semaphore
00046     void V();    // they are both *atomic*
00047     
00048   private:
00049     char* name;        // useful for debugging
00050     int value;         // semaphore value, always >= 0
00051     List *queue;       // threads waiting in P() for the value to be > 0
00052 };
00053 
00054 // The following class defines a "lock".  A lock can be BUSY or FREE.
00055 // There are only two operations allowed on a lock: 
00056 //
00057 //      Acquire -- wait until the lock is FREE, then set it to BUSY
00058 //
00059 //      Release -- set lock to be FREE, waking up a thread waiting
00060 //              in Acquire if necessary
00061 //
00062 // In addition, by convention, only the thread that acquired the lock
00063 // may release it.  As with semaphores, you can't read the lock value
00064 // (because the value might change immediately after you read it).  
00065 
00066 class Lock {
00067   public:
00068     Lock(char* debugName);              // initialize lock to be FREE
00069     ~Lock();                            // deallocate lock
00070     char* getName() { return name; }    // debugging assist
00071 
00072     void Acquire(); // these are the only operations on a lock
00073     void Release(); // they are both *atomic*
00074 
00075     bool isHeldByCurrentThread();       // true if the current thread
00076                                         // holds this lock.  Useful for
00077                                         // checking in Release, and in
00078                                         // Condition variable ops below.
00079 
00080   private:
00081     char* name;                         // for debugging
00082     // plus some other stuff you'll need to define
00083 };
00084 
00085 // The following class defines a "condition variable".  A condition
00086 // variable does not have a value, but threads may be queued, waiting
00087 // on the variable.  These are only operations on a condition variable: 
00088 //
00089 //      Wait() -- release the lock, relinquish the CPU until signaled, 
00090 //              then re-acquire the lock
00091 //
00092 //      Signal() -- wake up a thread, if there are any waiting on 
00093 //              the condition
00094 //
00095 //      Broadcast() -- wake up all threads waiting on the condition
00096 //
00097 // All operations on a condition variable must be made while
00098 // the current thread has acquired a lock.  Indeed, all accesses
00099 // to a given condition variable must be protected by the same lock.
00100 // In other words, mutual exclusion must be enforced among threads calling
00101 // the condition variable operations.
00102 //
00103 // In Nachos, condition variables are assumed to obey *Mesa*-style
00104 // semantics.  When a Signal or Broadcast wakes up another thread,
00105 // it simply puts the thread on the ready list, and it is the responsibility
00106 // of the woken thread to re-acquire the lock (this re-acquire is
00107 // taken care of within Wait()).  By contrast, some define condition
00108 // variables according to *Hoare*-style semantics -- where the signalling
00109 // thread gives up control over the lock and the CPU to the woken thread,
00110 // which runs immediately and gives back control over the lock to the 
00111 // signaller when the woken thread leaves the critical section.
00112 //
00113 // The consequence of using Mesa-style semantics is that some other thread
00114 // can acquire the lock, and change data structures, before the woken
00115 // thread gets a chance to run.
00116 
00117 class Condition {
00118   public:
00119     Condition(char* debugName);         // initialize condition to 
00120                                         // "no one waiting"
00121     ~Condition();                       // deallocate the condition
00122     char* getName() { return (name); }
00123     
00124     void Wait(Lock *conditionLock);     // these are the 3 operations on 
00125                                         // condition variables; releasing the 
00126                                         // lock and going to sleep are 
00127                                         // *atomic* in Wait()
00128     void Signal(Lock *conditionLock);   // conditionLock must be held by
00129     void Broadcast(Lock *conditionLock);// the currentThread for all of 
00130                                         // these operations
00131 
00132   private:
00133     char* name;
00134     // plus some other stuff you'll need to define
00135 };
00136 #endif // SYNCH_H

Generated on Mon Feb 10 09:54:47 2003 for nachos by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002
The University of Southern California does not screen or control the content on this website and thus does not guarantee the accuracy, integrity, or quality of such content. All content on this website is provided by and is the sole responsibility of the person from which such content originated, and such content does not necessarily reflect the opinions of the University administration or the Board of Trustees