1 CS 170 2 3 4 The previous handout demonstrated the use of mutexes. 5 This handout demonstrates the use of condition variables and monitors (which combine 6 mutexes and condition variables). 7 8 1. The bounded buffer as a monitor 9 10 // This is pseudocode that is inspired by C++. 11 // Don’t take it literally. 12 13 class MyBuffer { 14 public: 15 MyBuffer(); 16 ~MyBuffer(); 17 void Enqueue(Item); 18 Item = Dequeue(); 19 private: 20 int count; 21 int in; 22 int out; 23 Item buffer[BUFFER_SIZE]; 24 Mutex* mutex; 25 Cond* nonempty; 26 Cond* nonfull; 27 } 28 29 void 30 MyBuffer::MyBuffer() 31 { 32 in = out = count = 0; 33 mutex = new Mutex; 34 nonempty = new Cond; 35 nonfull = new Cond; 36 } 37 38 void 39 MyBuffer::Enqueue(Item item) 40 { 41 mutex.acquire(); 42 while (count == BUFFER_SIZE) 43 cond_wait(&nonfull, &mutex); 44 45 buffer[in] = item; 46 in = (in + 1) % BUFFER_SIZE; 47 ++count; 48 cond_signal(&nonempty, &mutex); 49 mutex.release(); 50 } 51 52 Item 53 MyBuffer::Dequeue() 54 { 55 mutex.acquire(); 56 while (count == 0) 57 cond_wait(&nonempty, &mutex); 58 59 Item ret = buffer[out]; 60 out = (out + 1) % BUFFER_SIZE; 61 −−count; 62 cond_signal(&nonfull, &mutex); 63 mutex.release(); 64 return ret; 65 } 66 67 68 int main(int, char**) 69 { 70 MyBuffer buf; 71 int dummy; 72 tid1 = thread_create(producer, &buf); 73 tid2 = thread_create(consumer, &buf); 74 75 // never reach this point 76 thread_join(tid1); 77 thread_join(tid2); 78 return −1; 79 } 80 81 void producer(void* buf) 82 { 83 MyBuffer* sharedbuf = reinterpret_cast(buf); 84 for (;;) { 85 /* next line produces an item and puts it in nextProduced */ 86 Item nextProduced = means_of_production(); 87 sharedbuf−>Enqueue(nextProduced); 88 } 89 } 90 91 void consumer(void* buf) 92 { 93 MyBuffer* sharedbuf = reinterpret_cast(buf); 94 for (;;) { 95 Item nextConsumed = sharedbuf−>Dequeue(); 96 97 /* next line abstractly consumes the item */ 98 consume_item(nextConsumed); 99 } 100 } 101 102 Key point: *Threads* (the producer and consumer) are separate from 103 *shared object* (MyBuffer). The synchronization happens in the 104 shared object. 105