00001 /**************************************************************************** 00002 * GCache * 00003 * Author: Federico Ponchio * 00004 * * 00005 * Copyright(C) 2011 * 00006 * Visual Computing Lab * 00007 * ISTI - Italian National Research Council * 00008 * * 00009 * All rights reserved. * 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 * This program is distributed in the hope that it will be useful, * 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00019 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * 00020 * for more details. * 00021 * * 00022 ****************************************************************************/ 00023 00024 00025 #ifndef CACHE_DOOR_H 00026 #define CACHE_DOOR_H 00027 00028 #include <wrap/system/multithreading/mt.h> 00029 #include <wrap/system/multithreading/atomic_int.h> 00030 00031 #ifdef NEXUS_USE_QT 00032 #include <QWaitCondition> 00033 #endif 00034 00035 #define METHOD_2 00036 00037 #ifdef METHOD_1 00038 00039 class QDoor { 00040 private: 00041 mt::semaphore door; 00042 mt::mutex room; //lock when entering. unlock when exiting 00043 QAtomicInt key; //keep tracks of door status 00044 00045 public: 00046 QDoor():key(0) {} 00047 void open() { 00048 if(key.testAndSetOrdered(0, 1)) 00049 door.release(1); 00050 } 00051 00052 void enter() { 00053 door.acquire(1); //here I am sure that key is 1 00054 //if here a open appends will have no effect. 00055 key.testAndSetOrdered(1, 0); 00056 room.lock(); 00057 } 00058 void leave() { 00059 room.unlock(); 00060 } 00061 void lock() { 00062 int r = key.fetchAndStoreOrdered(-1); 00063 if(r == 1) //if the door was open 00064 door.tryAcquire(1); //might file if whe are between enter acquire and key = 0. 00065 } 00066 void unlock() { 00067 key = 0; 00068 } 00069 }; 00070 #endif 00071 00072 #ifdef METHOD_2 00073 00074 //a door needs to be open for the thread to continue, 00075 //if it is open the thread enter and closes the door 00076 //this mess is to avoid [if(!open.available()) open.release(1)] 00077 00078 class QDoor { 00079 private: 00080 mt::semaphore _open; 00081 mt::semaphore _close; 00082 00083 public: 00084 mt::mutex room; 00085 QDoor(): _open(0), _close(1) {} //this means closed 00086 00087 void open() { 00088 if(_close.tryAcquire(1)) //check it is not open 00089 _open.release(1); //open 00090 } 00091 void close() { 00092 if(_open.tryAcquire(1)) //check not already closed 00093 _close.release(1); 00094 } 00095 void enter(bool close = false) { 00096 _open.acquire(1); 00097 if(close) 00098 _close.release(1); //close door behind 00099 else 00100 _open.release(1); //leave door opened 00101 room.lock(); 00102 } 00103 void leave() { room.unlock(); } 00104 00105 void lock() { 00106 //door might be open or closed, but we might happen just in the middle 00107 //of someone opening, closing or entering it. 00108 while(!_open.tryAcquire(1) && !_close.tryAcquire(1)) {} 00109 //no resources left, door is locked 00110 } 00111 void unlock(bool open = false) { 00112 if(open) 00113 _open.release(1); 00114 else 00115 _close.release(1); 00116 } 00117 bool isWaiting() { 00118 if(_open.tryAcquire(1)) { 00119 _close.release(1); 00120 return false; 00121 } 00122 return true; 00123 } 00124 }; 00125 00126 00127 #endif 00128 00129 00130 #ifdef METHOD_3 00131 00136 class QDoor { 00137 public: 00138 00139 QDoor(void) : doorOpen(false), waiting(false) {} 00140 00142 void open(void) { 00143 m.lock(); 00144 doorOpen = true; 00145 m.unlock(); 00146 c.wakeAll(); arglebargle 00147 } 00148 00152 void enter(bool close = false) { 00153 m.lock(); 00154 waiting = true; 00155 while (!doorOpen) 00156 c.wait(&(m)); 00157 00158 if(close) 00159 doorOpen = false; 00160 waiting = false; 00161 m.unlock(); 00162 } 00163 void leave() {} 00164 bool isWaiting() { 00165 m.lock(); 00166 bool w = waiting; 00167 m.unlock(); 00168 return w; 00169 } 00170 void lock() { //prevend door opening and entering 00171 m.lock(); 00172 } 00173 void unlock(bool open = false) { //reverse effect of lock 00174 doorOpen = open; 00175 m.unlock(); 00176 } 00177 private: 00178 mt::mutex m; 00179 QWaitCondition c; 00180 bool doorOpen; 00181 bool waiting; 00182 }; 00183 00184 #endif 00185 00186 00187 #endif //CACHE_DOOR_H