1 /**************************************************************************** 2 * GCache * 3 * Author: Federico Ponchio * 4 * * 5 * Copyright(C) 2011 * 6 * Visual Computing Lab * 7 * ISTI - Italian National Research Council * 8 * * 9 * All rights reserved. * 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 * This program is distributed in the hope that it will be useful, * 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * 20 * for more details. * 21 * * 22 ****************************************************************************/ 23 24 25 #ifndef CACHE_DOOR_H 26 #define CACHE_DOOR_H 27 28 #include <wrap/system/multithreading/mt.h> 29 #include <wrap/system/multithreading/atomic_int.h> 30 31 #ifdef NEXUS_USE_QT 32 #include <QWaitCondition> 33 #endif 34 35 #define METHOD_2 36 37 #ifdef METHOD_1 38 39 class QDoor { 40 private: 41 mt::semaphore door; 42 mt::mutex room; //lock when entering. unlock when exiting 43 QAtomicInt key; //keep tracks of door status 44 45 public: QDoor()46 QDoor():key(0) {} open()47 void open() { 48 if(key.testAndSetOrdered(0, 1)) 49 door.release(1); 50 } 51 enter()52 void enter() { 53 door.acquire(1); //here I am sure that key is 1 54 //if here a open appends will have no effect. 55 key.testAndSetOrdered(1, 0); 56 room.lock(); 57 } leave()58 void leave() { 59 room.unlock(); 60 } lock()61 void lock() { 62 int r = key.fetchAndStoreOrdered(-1); 63 if(r == 1) //if the door was open 64 door.tryAcquire(1); //might file if whe are between enter acquire and key = 0. 65 } unlock()66 void unlock() { 67 key = 0; 68 } 69 }; 70 #endif 71 72 #ifdef METHOD_2 73 74 //a door needs to be open for the thread to continue, 75 //if it is open the thread enter and closes the door 76 //this mess is to avoid [if(!open.available()) open.release(1)] 77 78 class QDoor { 79 private: 80 mt::semaphore _open; 81 mt::semaphore _close; 82 83 public: 84 mt::mutex room; QDoor()85 QDoor(): _open(0), _close(1) {} //this means closed 86 open()87 void open() { 88 if(_close.tryAcquire(1)) //check it is not open 89 _open.release(1); //open 90 } close()91 void close() { 92 if(_open.tryAcquire(1)) //check not already closed 93 _close.release(1); 94 } 95 void enter(bool close = false) { 96 _open.acquire(1); 97 if(close) 98 _close.release(1); //close door behind 99 else 100 _open.release(1); //leave door opened 101 room.lock(); 102 } leave()103 void leave() { room.unlock(); } 104 lock()105 void lock() { 106 //door might be open or closed, but we might happen just in the middle 107 //of someone opening, closing or entering it. 108 while(!_open.tryAcquire(1) && !_close.tryAcquire(1)) {} 109 //no resources left, door is locked 110 } 111 void unlock(bool open = false) { 112 if(open) 113 _open.release(1); 114 else 115 _close.release(1); 116 } isWaiting()117 bool isWaiting() { 118 if(_open.tryAcquire(1)) { 119 _close.release(1); 120 return false; 121 } 122 return true; 123 } 124 }; 125 126 127 #endif 128 129 130 #ifdef METHOD_3 131 /** 132 A wait condition class that works as a door. 133 Should check if the semaphore version is faster. 134 */ 135 136 class QDoor { 137 public: 138 QDoor(void)139 QDoor(void) : doorOpen(false), waiting(false) {} 140 141 ///opens the door. Threads trying to enter will be awakened open(void)142 void open(void) { 143 m.lock(); 144 doorOpen = true; 145 m.unlock(); 146 c.wakeAll(); arglebargle 147 } 148 149 ///attempt to enter the door. if the door is closed the thread will wait until the door is opened. 150 /// if close is true, the door will be closed after the thread is awakened, this allows to 151 /// have only one thread entering the door each time open() is called 152 void enter(bool close = false) { 153 m.lock(); 154 waiting = true; 155 while (!doorOpen) 156 c.wait(&(m)); 157 158 if(close) 159 doorOpen = false; 160 waiting = false; 161 m.unlock(); 162 } leave()163 void leave() {} isWaiting()164 bool isWaiting() { 165 m.lock(); 166 bool w = waiting; 167 m.unlock(); 168 return w; 169 } lock()170 void lock() { //prevend door opening and entering 171 m.lock(); 172 } 173 void unlock(bool open = false) { //reverse effect of lock 174 doorOpen = open; 175 m.unlock(); 176 } 177 private: 178 mt::mutex m; 179 QWaitCondition c; 180 bool doorOpen; 181 bool waiting; 182 }; 183 184 #endif 185 186 187 #endif //CACHE_DOOR_H 188