188 lines
5.2 KiB
C++
188 lines
5.2 KiB
C++
/****************************************************************************
|
|
* 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 <wrap/system/multithreading/mt.h>
|
|
#include <wrap/system/multithreading/atomic_int.h>
|
|
|
|
#ifdef QT_CORE_LIB
|
|
#include <QWaitCondition>
|
|
#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
|