tac0S
Template Affectional Command Operating System
synch.h
Go to the documentation of this file.
1 
20 #ifndef SYNCH_H
21 #define SYNCH_H
22 
23 #include "copyright.h"
24 #include "thread.h"
25 #include "list.h"
26 
41 
42 class Semaphore
43 {
44  public:
45  Semaphore (const char *debugName, int initialValue);// set initial value
46  ~Semaphore (); // de-allocate semaphore
47  const char *getName ()
48  {
49  return name;
50  } // debugging assist
51 
52  void P (); // these are the only operations on a semaphore
53  void V (); // they are both *atomic*
54 
55  private:
56  const char *name; // useful for debugging
57  int value; // semaphore value, always >= 0
58  List *queue; // threads waiting in P() for the value to be > 0
59 };
60 
61 // The following class defines a "lock". A lock can be BUSY or FREE.
62 // There are only two operations allowed on a lock:
63 //
64 // Acquire -- wait until the lock is FREE, then set it to BUSY
65 //
66 // Release -- set lock to be FREE, waking up a thread waiting
67 // in Acquire if necessary
68 //
69 // In addition, by convention, only the thread that acquired the lock
70 // may release it. As with semaphores, you can't read the lock value
71 // (because the value might change immediately after you read it).
72 
73 class Lock
74 {
75  public:
76  Lock (const char *debugName); // initialize lock to be FREE
77  ~Lock (); // deallocate lock
78  const char *getName ()
79  {
80  return name;
81  } // debugging assist
82 
83  void Acquire (); // these are the only operations on a lock
84  void Release (); // they are both *atomic*
85 
86  bool isHeldByCurrentThread (); // true if the current thread
87  // holds this lock. Useful for
88  // checking in Release, and in
89  // Condition variable ops below.
90 
91 
92  private:
93  const char *name; // for debugging
94  Thread * currentThreadHolding = NULL;
95  List * WaitingForLock;
96  // plus some other stuff you'll need to define
97 };
98 
99 // The following class defines a "condition variable". A condition
100 // variable does not have a value, but threads may be queued, waiting
101 // on the variable. These are only operations on a condition variable:
102 //
103 // Wait() -- release the lock, relinquish the CPU until signaled,
104 // then re-acquire the lock
105 //
106 // Signal() -- wake up a thread, if there are any waiting on
107 // the condition
108 //
109 // Broadcast() -- wake up all threads waiting on the condition
110 //
111 // All operations on a condition variable must be made while
112 // the current thread has acquired a lock. Indeed, all accesses
113 // to a given condition variable must be protected by the same lock.
114 // In other words, mutual exclusion must be enforced among threads calling
115 // the condition variable operations.
116 //
117 // In Nachos, condition variables are assumed to obey *Mesa*-style
118 // semantics. When a Signal or Broadcast wakes up another thread,
119 // it simply puts the thread on the ready list, and it is the responsibility
120 // of the woken thread to re-acquire the lock (this re-acquire is
121 // taken care of within Wait()). By contrast, some define condition
122 // variables according to *Hoare*-style semantics -- where the signalling
123 // thread gives up control over the lock and the CPU to the woken thread,
124 // which runs immediately and gives back control over the lock to the
125 // signaller when the woken thread leaves the critical section.
126 //
127 // The consequence of using Mesa-style semantics is that some other thread
128 // can acquire the lock, and change data structures, before the woken
129 // thread gets a chance to run.
130 
132 {
133  public:
134  Condition (const char *debugName); // initialize condition to
135  // "no one waiting"
136  ~Condition (); // deallocate the condition
137  const char *getName ()
138  {
139  return (name);
140  }
141 
142  void Wait (Lock * conditionLock); // these are the 3 operations on
143  // condition variables; releasing the
144  // lock and going to sleep are
145  // *atomic* in Wait()
146  void Signal (Lock * conditionLock); // conditionLock must be held by
147  void Broadcast (Lock * conditionLock); // the currentThread for all of
148  // these operations
149 
150  private:
151  const char *name;
152  // plus some other stuff you'll need to define
153 };
154 #endif // SYNCH_H
The following class defines a "thread control block" – which represents a single thread of execution...
Definition: thread.h:79
Data structures for managing threads.
Definition: list.h:46
Routines to manage a singly-linked list of "things". Defining TRUE and FALSE is usually a Bad Idea...
The following class defines a "semaphore" whose value is a non-negative integer. The semaphore has on...
Definition: synch.h:42
~Semaphore()
Semaphore::Semaphore De-allocate semaphore, when no longer needed. Assume no one is still waiting on ...
Definition: synch.cc:52
void P()
Semaphore::P Wait until semaphore value > 0, then decrement. Checking the value and decrementing must...
Definition: synch.cc:68
void V()
Semaphore::V Increment semaphore value, waking up a waiter if necessary. As with P(), this operation must be atomic, so we need to disable interrupts. Scheduler::ReadyToRun() assumes that threads are disabled when it is called.
Definition: synch.cc:98
Semaphore(const char *debugName, int initialValue)
Semaphore::Semaphore Initialize a semaphore, so that it can be used for synchronization.
Definition: synch.cc:39
Definition: synch.h:73
Definition: synch.h:131