vcglib/wrap/gcache/door.h

188 lines
5.2 KiB
C
Raw Normal View History

2011-03-11 17:14:54 +01:00
/****************************************************************************
* GCache *
* Author: Federico Ponchio *
* *
* Copyright(C) 2011 *
* Visual Computing Lab *
* ISTI - Italian National Research Council *
* *
* All rights reserved. *
* *
2011-11-26 19:08:30 +01:00
* This program is free software; you can redistribute it and/or modify *
2011-03-11 17:14:54 +01:00
* 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>
2011-12-14 20:22:17 +01:00
#include <wrap/system/multithreading/atomic_int.h>
2012-01-05 18:52:34 +01:00
#ifdef NEXUS_USE_QT
2011-11-29 13:41:28 +01:00
#include <QWaitCondition>
#endif
2011-11-29 13:41:28 +01:00
#define METHOD_2
#ifdef METHOD_1
class QDoor {
private:
mt::semaphore door;
mt::mutex room; //lock when entering. unlock when exiting
2011-11-29 13:41:28 +01:00
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
2011-03-11 17:14:54 +01:00
//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)]
2011-03-11 17:14:54 +01:00
class QDoor {
private:
mt::semaphore _open;
mt::semaphore _close;
2011-11-29 13:41:28 +01:00
2011-03-11 17:14:54 +01:00
public:
mt::mutex room;
2011-03-11 17:14:54 +01:00
QDoor(): _open(0), _close(1) {} //this means closed
2011-11-26 19:08:30 +01:00
2011-03-11 17:14:54 +01:00
void open() {
if(_close.tryAcquire(1)) //check it is not open
_open.release(1); //open
}
void close() {
2011-11-29 13:41:28 +01:00
if(_open.tryAcquire(1)) //check not already closed
2011-03-11 17:14:54 +01:00
_close.release(1);
}
void enter(bool close = false) {
_open.acquire(1);
if(close)
2011-11-26 19:08:30 +01:00
_close.release(1); //close door behind
2011-03-11 17:14:54 +01:00
else
2011-11-26 19:08:30 +01:00
_open.release(1); //leave door opened
2011-11-29 13:41:28 +01:00
room.lock();
2011-03-11 17:14:54 +01:00
}
2011-11-29 13:41:28 +01:00
void leave() { room.unlock(); }
2011-11-26 19:08:30 +01:00
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)) {}
2011-11-26 19:08:30 +01:00
//no resources left, door is locked
}
2011-11-26 19:08:30 +01:00
void unlock(bool open = false) {
if(open)
2011-11-29 13:41:28 +01:00
_open.release(1);
2011-11-26 19:08:30 +01:00
else
_close.release(1);
}
2011-11-29 13:41:28 +01:00
bool isWaiting() {
if(_open.tryAcquire(1)) {
_close.release(1);
return false;
}
return true;
}
2011-03-11 17:14:54 +01:00
};
2011-11-29 13:41:28 +01:00
#endif
2011-03-11 17:14:54 +01:00
2011-11-29 13:41:28 +01:00
#ifdef METHOD_3
2011-03-11 17:14:54 +01:00
/**
A wait condition class that works as a door.
Should check if the semaphore version is faster.
*/
class QDoor {
public:
2011-03-14 12:35:43 +01:00
QDoor(void) : doorOpen(false), waiting(false) {}
2011-03-11 17:14:54 +01:00
///opens the door. Threads trying to enter will be awakened
void open(void) {
2011-03-14 12:35:43 +01:00
m.lock();
doorOpen = true;
m.unlock();
2011-12-05 11:11:08 +01:00
c.wakeAll(); arglebargle
2011-03-11 17:14:54 +01:00
}
///attempt to enter the door. if the door is closed the thread will wait until the door is opened.
2011-11-29 13:41:28 +01:00
/// 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
2011-03-11 17:14:54 +01:00
void enter(bool close = false) {
2011-03-14 12:35:43 +01:00
m.lock();
waiting = true;
while (!doorOpen)
c.wait(&(m));
2011-11-26 19:08:30 +01:00
if(close)
2011-03-14 12:35:43 +01:00
doorOpen = false;
waiting = false;
m.unlock();
}
2011-11-29 13:41:28 +01:00
void leave() {}
2011-03-14 12:35:43 +01:00
bool isWaiting() {
m.lock();
bool w = waiting;
m.unlock();
return w;
2011-03-11 17:14:54 +01:00
}
2011-06-09 17:30:16 +02:00
void lock() { //prevend door opening and entering
m.lock();
}
2011-11-26 19:08:30 +01:00
void unlock(bool open = false) { //reverse effect of lock
doorOpen = open;
2011-06-09 17:30:16 +02:00
m.unlock();
}
2011-03-11 17:14:54 +01:00
private:
mt::mutex m;
2011-03-11 17:14:54 +01:00
QWaitCondition c;
bool doorOpen;
2011-03-14 12:35:43 +01:00
bool waiting;
2011-03-11 17:14:54 +01:00
};
2011-11-29 13:41:28 +01:00
#endif
2011-03-11 17:14:54 +01:00
#endif //CACHE_DOOR_H