00001 // synchlist.cc 00002 // Routines for synchronized access to a list. 00003 // 00004 // Implemented in "monitor"-style -- surround each procedure with a 00005 // lock acquire and release pair, using condition signal and wait for 00006 // synchronization. 00007 // 00008 // Copyright (c) 1992-1993 The Regents of the University of California. 00009 // All rights reserved. See copyright.h for copyright notice and limitation 00010 // of liability and disclaimer of warranty provisions. 00011 00012 #include "copyright.h" 00013 #include "synchlist.h" 00014 00015 //---------------------------------------------------------------------- 00016 // SynchList<T>::SynchList 00017 // Allocate and initialize the data structures needed for a 00018 // synchronized list, empty to start with. 00019 // Elements can now be added to the list. 00020 //---------------------------------------------------------------------- 00021 00022 template <class T> 00023 SynchList<T>::SynchList() 00024 { 00025 list = new List<T>; 00026 lock = new Lock("list lock"); 00027 listEmpty = new Condition("list empty cond",lock); 00028 } 00029 00030 //---------------------------------------------------------------------- 00031 // SynchList<T>::~SynchList 00032 // De-allocate the data structures created for synchronizing a list. 00033 //---------------------------------------------------------------------- 00034 00035 template <class T> 00036 SynchList<T>::~SynchList() 00037 { 00038 delete listEmpty; 00039 delete lock; 00040 delete list; 00041 } 00042 00043 //---------------------------------------------------------------------- 00044 // SynchList<T>::Append 00045 // Append an "item" to the end of the list. Wake up anyone 00046 // waiting for an element to be appended. 00047 // 00048 // "item" is the thing to put on the list. 00049 //---------------------------------------------------------------------- 00050 00051 template <class T> 00052 void 00053 SynchList<T>::Append(T item) 00054 { 00055 lock->Acquire(); // enforce mutual exclusive access to the list 00056 list->Append(item); 00057 listEmpty->Signal(); // wake up a waiter, if any 00058 lock->Release(); 00059 } 00060 00061 //---------------------------------------------------------------------- 00062 // SynchList<T>::RemoveFront 00063 // Remove an "item" from the beginning of the list. Wait if 00064 // the list is empty. 00065 // Returns: 00066 // The removed item. 00067 //---------------------------------------------------------------------- 00068 00069 template <class T> 00070 T 00071 SynchList<T>::RemoveFront() 00072 { 00073 T item; 00074 00075 lock->Acquire(); // enforce mutual exclusion 00076 while (list->IsEmpty()) 00077 listEmpty->Wait(); // wait until list isn't empty 00078 item = list->RemoveFront(); 00079 lock->Release(); 00080 return item; 00081 } 00082 00083 //---------------------------------------------------------------------- 00084 // SynchList<T>::Apply 00085 // Apply function to every item on a list. 00086 // 00087 // "func" -- the function to apply 00088 //---------------------------------------------------------------------- 00089 00090 template <class T> 00091 void 00092 SynchList<T>::Apply(void (*func)(T)) 00093 { 00094 lock->Acquire(); // enforce mutual exclusion 00095 list->Apply(func); 00096 lock->Release(); 00097 } 00098 00099 //---------------------------------------------------------------------- 00100 // SynchList<T>::SelfTest, SelfTestHelper 00101 // Test whether the SynchList implementation is working, 00102 // by having two threads ping-pong a value between them 00103 // using two synchronized lists. 00104 //---------------------------------------------------------------------- 00105 00106 template <class T> 00107 void 00108 SynchList<T>::SelfTestHelper (void* data) 00109 { 00110 SynchList<T>* _this = (SynchList<T>*)data; 00111 for (int i = 0; i < 10; i++) { 00112 _this->Append(_this->selfTestPing->RemoveFront()); 00113 } 00114 } 00115 00116 template <class T> 00117 void 00118 SynchList<T>::SelfTest(T val) 00119 { 00120 Thread *helper = new Thread("ping"); 00121 00122 ASSERT(list->IsEmpty()); 00123 selfTestPing = new SynchList<T>; 00124 helper->Fork(SynchList<T>::SelfTestHelper, this); 00125 for (int i = 0; i < 10; i++) { 00126 selfTestPing->Append(val); 00127 ASSERT(val == this->RemoveFront()); 00128 } 00129 delete selfTestPing; 00130 }