/**************************************************************************** * GCache * * Author: Federico Ponchio * * * * Copyright(C) 2011 * * Visual Computing Lab * * ISTI - Italian National Research Council * * * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef CACHE_DOOR_H #define CACHE_DOOR_H #include #include #ifdef NEXUS_USE_QT #include #endif #define METHOD_2 #ifdef METHOD_1 class QDoor { private: mt::semaphore door; mt::mutex room; //lock when entering. unlock when exiting QAtomicInt key; //keep tracks of door status public: QDoor():key(0) {} void open() { if(key.testAndSetOrdered(0, 1)) door.release(1); } void enter() { door.acquire(1); //here I am sure that key is 1 //if here a open appends will have no effect. key.testAndSetOrdered(1, 0); room.lock(); } void leave() { room.unlock(); } void lock() { int r = key.fetchAndStoreOrdered(-1); if(r == 1) //if the door was open door.tryAcquire(1); //might file if whe are between enter acquire and key = 0. } void unlock() { key = 0; } }; #endif #ifdef METHOD_2 //a door needs to be open for the thread to continue, //if it is open the thread enter and closes the door //this mess is to avoid [if(!open.available()) open.release(1)] class QDoor { private: mt::semaphore _open; mt::semaphore _close; public: mt::mutex room; QDoor(): _open(0), _close(1) {} //this means closed void open() { if(_close.tryAcquire(1)) //check it is not open _open.release(1); //open } void close() { if(_open.tryAcquire(1)) //check not already closed _close.release(1); } void enter(bool close = false) { _open.acquire(1); if(close) _close.release(1); //close door behind else _open.release(1); //leave door opened room.lock(); } void leave() { room.unlock(); } void lock() { //door might be open or closed, but we might happen just in the middle //of someone opening, closing or entering it. while(!_open.tryAcquire(1) && !_close.tryAcquire(1)) {} //no resources left, door is locked } void unlock(bool open = false) { if(open) _open.release(1); else _close.release(1); } bool isWaiting() { if(_open.tryAcquire(1)) { _close.release(1); return false; } return true; } }; #endif #ifdef METHOD_3 /** A wait condition class that works as a door. Should check if the semaphore version is faster. */ class QDoor { public: QDoor(void) : doorOpen(false), waiting(false) {} ///opens the door. Threads trying to enter will be awakened void open(void) { m.lock(); doorOpen = true; m.unlock(); c.wakeAll(); arglebargle } ///attempt to enter the door. if the door is closed the thread will wait until the door is opened. /// if close is true, the door will be closed after the thread is awakened, this allows to /// have only one thread entering the door each time open() is called void enter(bool close = false) { m.lock(); waiting = true; while (!doorOpen) c.wait(&(m)); if(close) doorOpen = false; waiting = false; m.unlock(); } void leave() {} bool isWaiting() { m.lock(); bool w = waiting; m.unlock(); return w; } void lock() { //prevend door opening and entering m.lock(); } void unlock(bool open = false) { //reverse effect of lock doorOpen = open; m.unlock(); } private: mt::mutex m; QWaitCondition c; bool doorOpen; bool waiting; }; #endif #endif //CACHE_DOOR_H