mitsuba/include/mitsuba/core/lock.h

243 lines
5.4 KiB
C++

/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2014 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined(__MITSUBA_CORE_LOCK_H_)
#define __MITSUBA_CORE_LOCK_H_
#include <mitsuba/mitsuba.h>
#include <boost/scoped_ptr.hpp>
MTS_NAMESPACE_BEGIN
/**
* \brief Thin wrapper around the recursive boost thread lock
*
* \ingroup libcore
*/
class MTS_EXPORT_CORE Mutex : public Object {
friend class ConditionVariable;
public:
/// Create a new mutex object
Mutex();
/// Lock the mutex
void lock();
/// Unlock the mutex
void unlock();
MTS_DECLARE_CLASS()
protected:
/// Virtual destructor
virtual ~Mutex();
private:
struct MutexPrivate;
boost::scoped_ptr<MutexPrivate> d;
};
/**
* \brief Wait flag synchronization primitive. Can be used to
* wait for a certain event to occur.
*
* \ingroup libcore
*/
class MTS_EXPORT_CORE WaitFlag : public Object {
public:
/**
* \brief Create a new wait flag
* \param flag
* Initial state of the flag. If set to true, \ref wait()
* will immediately return.
*/
WaitFlag(bool flag = false);
/// Return the current flag value
const bool &get() const;
/// Set the value of the flag
void set(bool value);
/// Wait for the flag to be set to true
void wait();
/**
* \brief Temporarily wait for the flag to be set to true
*
* Similar to \ref wait(), but also uses a time value given
* in milliseconds. A return value of \c false signals
* that a timeout has occurred.
*
* \param ms Maximum waiting time in milliseconds
*/
bool wait(int ms);
MTS_DECLARE_CLASS()
protected:
/// Virtual destructor
virtual ~WaitFlag();
private:
struct WaitFlagPrivate;
boost::scoped_ptr<WaitFlagPrivate> d;
};
/**
* \brief Condition variable synchronization primitive. Can be used to
* wait for a condition to become true in a safe way.
*
* \ingroup libcore
*/
class MTS_EXPORT_CORE ConditionVariable : public Object {
public:
/**
* \brief Create a new condition variable. Also takes a
* mutex, which is later used by wait(). If none is specified,
* a new mutex instance will be created.
*/
ConditionVariable(Mutex *mutex = NULL);
/**
* \brief Send a signal, which wakes up at least one of
* the waiting threads.
*
* The calling thread does not have to hold the lock,
* but more predictable scheduling will occur if this is the
* case.
*/
void signal();
/**
* \brief Send a signal, which wakes up any waiting threads.
*
* The calling thread does not have to hold the lock, but more
* predictable scheduling will occur if this is the case.
*/
void broadcast();
/**
* \brief Wait for a signal and release the lock in the meanwhile.
*
* Assumes that the lock specified in the constructor has
* previously been acquired. After returning, the lock is
* held again.
*/
void wait();
/**
* \brief Temporarily wait for a signal and release the lock in the meanwhile.
*
* Similar to wait(), but also uses a time value given
* in milliseconds. A return value of \c false signals
* that a timeout has occurred. The lock is held after
* returning in either case.
*
* \param ms Maximum waiting time in milliseconds
*/
bool wait(int ms);
MTS_DECLARE_CLASS()
protected:
/// Virtual destructor
virtual ~ConditionVariable();
private:
struct ConditionVariablePrivate;
boost::scoped_ptr<ConditionVariablePrivate> d;
};
/**
* \brief Simple RAII-style locking of a Mutex. On construction it locks the
* mutex and unlocks it on destruction. Based on boost::lock_guard,
* assumes the Mutex will outlive the lock.
*
* \ingroup libcore
*/
class LockGuard {
public:
explicit LockGuard(Mutex * m_) : m(m_) {
m->lock();
}
~LockGuard() {
m->unlock();
}
private:
Mutex* const m;
explicit LockGuard(LockGuard&);
LockGuard& operator=(LockGuard&);
};
/**
* \brief In addition to providing RAII-style locking, UniqueLock also allows
* for deferred locking until lock() is called explicitly. unlock() is only
* called by the destructor if the object has locked the mutex.
* Based on boost::unique_lock, assumes the Mutex will outlive the lock.
*/
class UniqueLock {
public:
explicit UniqueLock(Mutex * mutex, bool acquire_lock = true)
: m(mutex), is_locked(false) {
if (acquire_lock)
lock();
}
~UniqueLock() {
if (ownsLock())
m->unlock();
}
void lock() {
SAssert(!ownsLock() && m != NULL);
m->lock();
is_locked = true;
}
void unlock() {
SAssert(ownsLock() && m != NULL);
m->unlock();
is_locked = false;
}
Mutex * release() {
Mutex * const mutex = m;
m = static_cast<Mutex*>(NULL);
is_locked = false;
return mutex;
}
inline bool operator!() const {
return !ownsLock();
}
inline bool ownsLock() const {
return is_locked;
}
private:
Mutex* m;
bool is_locked;
explicit UniqueLock(UniqueLock&);
UniqueLock& operator=(UniqueLock&);
};
MTS_NAMESPACE_END
#endif /* __MITSUBA_CORE_LOCK_H_ */