Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members

RoomSynchronizer.h

Go to the documentation of this file.
00001 /******************************************************************************** 00002 * NOTE: I NEVER USED THIS TEMPLATE. 00003 * 00004 * I RELEAZED I DIDN'T NEED IT RIGHT AFTER CODING IT. 00005 * 00006 * IT'S NOT DEBUGGED AT ALL, AND MIGHT EVEN NOT COMPILE. 00007 * 00008 * ALSO, IF YOU LOOK IN FifoCriticalSection.C, YOU'LL SEE A MORE EFFICIENT WAY 00009 * TO IMPLEMENT THIS USING PtCondition OBJECTS AND JUST ONE PtMutex. 00010 * 00011 * 00012 * -CJC 00013 * 00014 *******************************************************************************/ 00015 00016 #ifndef ROOMSYNCHRONIZER_H 00017 #define ROOMSYNCHRONIZER_H 00018 00019 #include <exception> 00020 #include <vector> 00021 00022 #include <PtMutex.h> 00023 #include <BinarySem.h> 00024 #include <LockHolder.h> 00025 00026 using namespace std; 00027 00028 // TRoomEnum is a enum giving all of the possible room names. 00029 // 00030 // We ensure the following with this class: 00031 // - Only one room at a time contains running threads. 00032 // - Room entrance is granted in first-come-first-serve order. 00033 // 00034 // Since this synchronizer uses locking, a wayward thread in a room can starve 00035 // all other threads trying to enter the synchronizer. 00036 00037 template 00038 class RoomSynchronizer<typename TRoomEnum> 00039 { 00040 public: 00041 RoomSynchronizer() 00042 throw (exception); 00043 00044 // There must not be any threads currently waiting for rooms when this is 00045 // called. 00046 virtual ~RoomSynchronizer(); 00047 00048 // Blocks until the room can be entered. 00049 // 00050 // You must always call exitRoom(...) after one call of this method, before 00051 // making another call to this method. 00052 void enterRoom(TRoomEnum desiredRoom) 00053 throw (exception); 00054 00055 void exitRoom() 00056 throw (exception); 00057 00058 private: 00059 // Shortly held mutex just to let this class be threadsafe. 00060 PtMutex _mtx; 00061 00062 // Iff _threadsInCurrentRoom > 0, _currentRoom says which room those threads 00063 // are in. 00064 size_t _threadsInCurrentRoom; 00065 TRoomEnum _currentRoom; 00066 00067 00068 struct WaiterInfo 00069 { 00070 WaiterInfo(TRoomEnum desiredRoom, BinarySem * pEnterRoomSignal) : 00071 _desiredRoom(desiredRoom), 00072 _pEnterRoomSignal(pEnterRoomSignal) 00073 { 00074 } 00075 00076 TRoomEnum _desiredRoom; 00077 BinarySem * _pEnterRoomSignal; 00078 }; 00079 00080 00081 // This is for threads that want to enter rooms, but couldn't yet because of 00082 // current room occupancy. _waiters[0] is the next thread to enter a room, 00083 // _waiters[1] is the next, etc. 00084 vector<WaiterInfo> _waiters; 00085 }; 00086 00087 //=============================================================================== 00088 00089 template 00090 RoomSynchronizer<typename TRoomEnum>::RoomSynchronizer() 00091 throw (exception) 00092 { 00093 _threadsInCurrentRoom = 0; 00094 } 00095 00096 //=============================================================================== 00097 00098 template 00099 RoomSynchronizer<typename TRoomEnum>::~RoomSynchronizer() 00100 { 00101 assert(_waiters.size() == 0); 00102 } 00103 00104 //=============================================================================== 00105 00106 template 00107 void RoomSynchronizer<typename TRoomEnum>::enterRoom(TRoomEnum desiredRoom) 00108 throw (exception) 00109 { 00110 BinarySem * pWaitSem = NULL; 00111 00112 LockHolder lh(_mtx); 00113 00114 if (_threadsInCurrentRoom == 0) 00115 { 00116 _threadsInCurrentRoom = 1; 00117 _currentRoom = desiredRoom; 00118 } 00119 else if (_waiters.size() == 0) 00120 { 00121 // There's at least the possibility that we can enter the room... 00122 if (_currentRoom == desiredRoom) 00123 { 00124 ++ _threadsInCurrentRoom; 00125 } 00126 else 00127 { 00128 pWaitSem = new BinarySem; 00129 _waiters.push_back(WaiterInfo(desiredRoom, pWaitSem)); 00130 } 00131 } 00132 00133 // Do we have to wait to enter the room? 00134 if (pWaitSem != NULL) 00135 { 00136 lh.release(); 00137 pWaitSem->awaitPost(); 00138 delete pWaitSem; 00139 lh.reacquire(); 00140 00141 00142 TODO!!! Need to remove myself from _waiters, because I'm no longe a waiter! 00143 This problably means we need to use a list, not a vector, for _waiters. -cjc 00144 00145 // Go ahead and enter the room... 00146 assert((_currentRoom == desiredRoom) || (_threadsInCurrentRoom == 0)); 00147 00148 ++ _threadsInCurrentRoom; 00149 00150 // The assignment is a no-op in case where 00151 // _currentRoom == desiredRoom, 00152 // 00153 _currentRoom = desiredRoom; 00154 } 00155 } 00156 00157 00158 //=============================================================================== 00159 00160 template 00161 void RoomSynchronizer<typename TRoomEnum>::exitRoom() 00162 throw (exception) 00163 { 00164 LockHolder lh(_mtx); 00165 00166 -- _threadsInCurrentRoom; 00167 00168 // If we're vacating a room, let one or more waiters into the house... 00169 if ((_threadsInCurrentRoom == 0) && (! _waiters.empty())) 00170 { 00171 _currentRoom = _waiters[0]._desiredRoom; 00172 00173 size_t numWaiters = _waiters.size(); 00174 for (size_t i = 0; 00175 (i < numWaiters) && (_waiters[i]._desiredRoom == _currentRoom); 00176 ++ i) 00177 { 00178 ++ _threadsInCurrentRoom; 00179 _waiters[i]._pEnterRoomSignal->post(); 00180 } 00181 } 00182 } 00183 00184 //=============================================================================== 00185 00186 #endif

Generated on Fri Nov 12 15:15:21 2004 for Borealis by doxygen 1.3.8