Starting from 2021-07-01, all LRZ GitLab users will be required to explicitly accept the GitLab Terms of Service. Please see the detailed information at https://doku.lrz.de/display/PUBLIC/GitLab and make sure that your projects conform to the requirements.

Commit fc9111ee authored by schultezub's avatar schultezub
Browse files

introduced usage of mutexes in GenericProperty, DataHandle and DataContainer

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@184 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent 1f2337cb
......@@ -17,20 +17,24 @@ namespace TUMVis {
const DataHandle* DataContainer::addData(const std::string& name, AbstractData* data) {
DataHandle* dh = new DataHandle(this, data);
tbb::spin_mutex::scoped_lock lock(_localMutex);
_handles.insert(std::make_pair(name, dh));
return dh;
}
void DataContainer::addDataHandle(const std::string& name, const DataHandle* dh) {
tbb::spin_mutex::scoped_lock lock(_localMutex);
_handles.insert(std::make_pair(name, dh));
DataHandle::addOwner(dh, this);
}
bool DataContainer::hasData(const std::string& name) const {
tbb::spin_mutex::scoped_lock lock(_localMutex);
return (_handles.find(name) != _handles.end());
}
const DataHandle* DataContainer::getData(const std::string& name) const {
tbb::spin_mutex::scoped_lock lock(_localMutex);
std::map<std::string, const DataHandle*>::const_iterator it = _handles.find(name);
if (it == _handles.end())
return 0;
......
#ifndef DATACONTAINER_H__
#define DATACONTAINER_H__
#include "tbb/include/tbb/spin_mutex.h"
#include "core/datastructures/abstractdata.h"
#include "core/datastructures/datahandle.h"
......@@ -15,8 +16,9 @@ namespace TUMVis {
* as soon as an AbstractData instance is added to a DataContainer via DataContainer::addData(), its
* lifetime is managed by the wrapping DataHandle instance.
* Because the DataHandles are stored as const handles, the underlying data cannot be changed anymore. This
* also ensures (hopefully) that nobody can do messy things, such as adding the same AbstractData instance
* twice to a DataContainer (which would really mess up the lifetime management!).
* also ensures (hopefully) that nobody can do messy things, such as changing the data while some other
* thread is reading it or adding the same AbstractData instance twice to a DataContainer (which would
* really mess up the lifetime management!).
*
* \todo We definately want thread-safety here!
*
......@@ -75,6 +77,7 @@ namespace TUMVis {
private:
std::map<std::string, const DataHandle*> _handles;
mutable tbb::spin_mutex _localMutex;
static const std::string loggerCat_;
};
......
#include "datahandle.h"
#include "tgt/assert.h"
namespace TUMVis {
const std::string DataHandle::loggerCat_ = "TUMVis.core.datastructures.DataHandle";
......@@ -10,31 +11,21 @@ namespace TUMVis {
addOwner(this, owner);
}
DataHandle::DataHandle(const DataHandle& /*rhs*/) {
// IMHO a DataHandle does not need a copy-constructor - in particular it could be a bad idea to use
// one, because it does not exactly what you expect. If you really need a copy-constructor, please
// make sure to implement it correctly. From my current point of view, you at least need to clone
// _data but then you still don't know anything about any owners of the new DataHandle.
LERROR("Do you really want to use the copy-constructor? If so, please implement it yourself, but beware: This might be dangerous...");
}
DataHandle& DataHandle::operator=(const DataHandle& /*rhs*/) {
// IMHO a DataHandle does not need an assignment-operator - in particular it could be a bad idea to use
// one, because it does not exactly what you expect. If you really need an assignment-operator, please
// make sure to implement it correctly.
LERROR("Do you really want to use the assignment-operator? If so, please implement it yourself, but beware: This might be dangerous...");
return *this; //< of course this is evil - just want to make the compiler happy...
}
DataHandle::~DataHandle() {
delete _data;
}
void DataHandle::addOwner(const DataHandle* handle, const DataContainer* owner) {
tgtAssert(handle != 0, "Handle must not be 0!");
tgtAssert(owner != 0, "Owning DataContainer must not be 0!");
tbb::spin_mutex::scoped_lock lock(handle->_localMutex);
handle->_owners.insert(owner);
}
void DataHandle::removeOwner(const DataHandle* handle, const DataContainer* owner) {
tgtAssert(handle != 0, "Handle must not be 0!");
tgtAssert(owner != 0, "Owning DataContainer must not be 0!");
tbb::spin_mutex::scoped_lock lock(handle->_localMutex);
handle->_owners.erase(owner);
if (handle->_owners.empty()) {
delete handle;
......
#ifndef datahandle_h__
#define datahandle_h__
#include "tbb/include/tbb/spin_mutex.h"
#include "tgt/logmanager.h"
#include "core/datastructures/abstractdata.h"
......@@ -93,8 +94,9 @@ namespace TUMVis {
static void removeOwner(const DataHandle* handle, const DataContainer* owner);
AbstractData* _data; ///< managed data
AbstractData* const _data; ///< managed data
mutable std::set<const DataContainer*> _owners; ///< set of owners of this DataHandle
mutable tbb::spin_mutex _localMutex; ///< Mutex used when altering local members
static const std::string loggerCat_;
};
......
#ifndef GENERICPROPERTY_H__
#define GENERICPROPERTY_H__
#include "tbb/include/tbb/spin_mutex.h"
#include "tgt/logmanager.h"
#include "core/properties/abstractproperty.h"
......@@ -10,7 +11,7 @@ namespace TUMVis {
* Generic class for value-based properties.
*
* \tparam T Base type of the property's value.
* \todo Add PropertyWidgets
* \todo Add PropertyWidgets, review use of mutex
*/
template<typename T>
class GenericProperty : public AbstractProperty {
......@@ -50,13 +51,48 @@ namespace TUMVis {
/**
* Sets the property value to \a value and notifies all observers.
* Depending on the current lock state of the property, the value will either be written to the front or back buffer.
* \param value New value for this property.
*/
void setValue(const T& value);
/**
* Locks the property and marks it as "in use". All changes to its value will be written to
* the back buffer. The buffers will be swapped on unlocking the property.
* \sa GenericProperty::unlock
*/
void lock();
/**
* Unlocks the property. If the back buffer has changed, the changes will be written to the front
* buffer and all observers will be notified.
* \sa GenericProperty::lock
*/
void unlock();
protected:
T _value; ///< value of the property
/**
* Sets the property value to \a value and notifies all observers.
* \note _localMutex has to be acquired before calling!
* \param value New value for _value.
*/
void setFrontValue(const T& value);
/**
* Sets the property's back buffer value to \a value.
* \note _localMutex has to be acquired before calling!
* \param value New value for _backBuffer.
*/
void setBackValue(const T& value);
T _value; ///< value of the property
T _backBuffer; ///< back buffer for values when property is in use
bool _inUse; ///< flag whether property is currently in use and values are written to back buffer
tbb::spin_mutex _localMutex; ///< Mutex used when altering local members
static const std::string loggerCat_;
};
......@@ -67,6 +103,8 @@ namespace TUMVis {
TUMVis::GenericProperty<T>::GenericProperty(const std::string& name, const std::string& title, const T& value, InvalidationLevel il /*= InvalidationLevel::INVALID_RESULT*/)
: AbstractProperty(name, title, il)
, _value(value)
, _backBuffer(value)
, _inUse(false)
{
}
......@@ -93,6 +131,31 @@ namespace TUMVis {
template<typename T>
void TUMVis::GenericProperty<T>::setValue(const T& value) {
tbb::spin_mutex::scoped_lock lock(_intrinsicsMutex);
if (_inUse)
setBackValue(value);
else
setFrontValue(value);
}
template<typename T>
void TUMVis::GenericProperty<T>::lock() {
tbb::spin_mutex::scoped_lock lock(_intrinsicsMutex);
_inUse = true;
}
template<typename T>
void TUMVis::GenericProperty<T>::unlock() {
tbb::spin_mutex::scoped_lock lock(_intrinsicsMutex);
if (_backBuffer != _value)
setFrontValue(_backBuffer);
_inUse = false;
}
template<typename T>
void TUMVis::GenericProperty<T>::setFrontValue(const T& value) {
_value = value;
// TODO: think about the correct/reasonable order of observer notification
// thread-safety might play a role thereby...
......@@ -105,6 +168,11 @@ namespace TUMVis {
notifyObservers(PropertyObserverArgs(this, _invalidationLevel));
}
template<typename T>
void TUMVis::GenericProperty<T>::setBackValue(const T& value) {
_backBuffer = value;
}
template<typename T>
const std::string TUMVis::GenericProperty<T>::loggerCat_ = "TUMVis.core.datastructures.GenericProperty";
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment