You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
4.7 KiB
C++
207 lines
4.7 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkSMPThreadLocalObject.h
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=========================================================================*/
|
|
/**
|
|
* @class vtkSMPThreadLocalObject
|
|
* @brief Thread local storage for VTK objects.
|
|
*
|
|
* This class essentially does the same thing as vtkSMPThreadLocal with
|
|
* 2 additional functions:
|
|
* - Local() allocates an object of the template argument type using ::New
|
|
* - The destructor calls Delete() on all objects created with Local().
|
|
*
|
|
* @warning
|
|
* There is absolutely no guarantee to the order in which the local objects
|
|
* will be stored and hence the order in which they will be traversed when
|
|
* using iterators. You should not even assume that two vtkSMPThreadLocal
|
|
* populated in the same parallel section will be populated in the same
|
|
* order. For example, consider the following
|
|
* \verbatim
|
|
* vtkSMPThreadLocal<int> Foo;
|
|
* vtkSMPThreadLocal<int> Bar;
|
|
* class AFunctor
|
|
* {
|
|
* void Initialize() const
|
|
* {
|
|
* int& foo = Foo.Local();
|
|
* int& bar = Bar.Local();
|
|
* foo = random();
|
|
* bar = foo;
|
|
* }
|
|
*
|
|
* @warning
|
|
* void operator()(vtkIdType, vtkIdType)
|
|
* {}
|
|
* void Finalize()
|
|
* {}
|
|
* };
|
|
*
|
|
* @warning
|
|
* AFunctor functor;
|
|
* vtkSMPTools::For(0, 100000, functor);
|
|
*
|
|
* @warning
|
|
* vtkSMPThreadLocal<int>::iterator itr1 = Foo.begin();
|
|
* vtkSMPThreadLocal<int>::iterator itr2 = Bar.begin();
|
|
* while (itr1 != Foo.end())
|
|
* {
|
|
* assert(*itr1 == *itr2);
|
|
* ++itr1; ++itr2;
|
|
* }
|
|
* \endverbatim
|
|
*
|
|
* @warning
|
|
* It is possible and likely that the assert() will fail using the TBB
|
|
* backend. So if you need to store values related to each other and
|
|
* iterate over them together, use a struct or class to group them together
|
|
* and use a thread local of that class.
|
|
*
|
|
* @sa
|
|
* vtkSMPThreadLocal
|
|
*/
|
|
|
|
#ifndef vtkSMPThreadLocalObject_h
|
|
#define vtkSMPThreadLocalObject_h
|
|
|
|
#include "vtkSMPThreadLocal.h"
|
|
|
|
template <typename T>
|
|
class vtkSMPThreadLocalObject
|
|
{
|
|
typedef vtkSMPThreadLocal<T*> TLS;
|
|
typedef typename vtkSMPThreadLocal<T*>::iterator TLSIter;
|
|
|
|
// Hide the copy constructor for now and assignment
|
|
// operator for now.
|
|
vtkSMPThreadLocalObject(const vtkSMPThreadLocalObject&);
|
|
void operator=(const vtkSMPThreadLocalObject&);
|
|
|
|
public:
|
|
/**
|
|
* Default constructor.
|
|
*/
|
|
vtkSMPThreadLocalObject()
|
|
: Internal(nullptr)
|
|
, Exemplar(nullptr)
|
|
{
|
|
}
|
|
|
|
vtkSMPThreadLocalObject(T* const& exemplar)
|
|
: Internal(0)
|
|
, Exemplar(exemplar)
|
|
{
|
|
}
|
|
|
|
virtual ~vtkSMPThreadLocalObject()
|
|
{
|
|
iterator iter = this->begin();
|
|
while (iter != this->end())
|
|
{
|
|
if (*iter)
|
|
{
|
|
(*iter)->Delete();
|
|
}
|
|
++iter;
|
|
}
|
|
}
|
|
|
|
//@{
|
|
/**
|
|
* Returns an object local to the current thread.
|
|
* This object is allocated with ::New() and will
|
|
* be deleted in the destructor of vtkSMPThreadLocalObject.
|
|
*/
|
|
T*& Local()
|
|
{
|
|
T*& vtkobject = this->Internal.Local();
|
|
if (!vtkobject)
|
|
{
|
|
if (this->Exemplar)
|
|
{
|
|
vtkobject = this->Exemplar->NewInstance();
|
|
}
|
|
else
|
|
{
|
|
vtkobject = T::SafeDownCast(T::New());
|
|
}
|
|
}
|
|
return vtkobject;
|
|
}
|
|
//@}
|
|
|
|
/**
|
|
* Return the number of thread local objects that have been initialized
|
|
*/
|
|
size_t size() const { return this->Internal.size(); }
|
|
|
|
//@{
|
|
/**
|
|
* Subset of the standard iterator API.
|
|
* The most common design pattern is to use iterators in a sequential
|
|
* code block and to use only the thread local objects in parallel
|
|
* code blocks.
|
|
*/
|
|
class iterator
|
|
{
|
|
public:
|
|
iterator& operator++()
|
|
{
|
|
++this->Iter;
|
|
return *this;
|
|
}
|
|
//@}
|
|
|
|
iterator operator++(int)
|
|
{
|
|
iterator copy = *this;
|
|
++this->Iter;
|
|
return copy;
|
|
}
|
|
|
|
bool operator==(const iterator& other) { return this->Iter == other.Iter; }
|
|
|
|
bool operator!=(const iterator& other) { return this->Iter != other.Iter; }
|
|
|
|
T*& operator*() { return *this->Iter; }
|
|
|
|
T** operator->() { return &*this->Iter; }
|
|
|
|
private:
|
|
TLSIter Iter;
|
|
|
|
friend class vtkSMPThreadLocalObject<T>;
|
|
};
|
|
|
|
iterator begin()
|
|
{
|
|
iterator iter;
|
|
iter.Iter = this->Internal.begin();
|
|
return iter;
|
|
};
|
|
|
|
iterator end()
|
|
{
|
|
iterator iter;
|
|
iter.Iter = this->Internal.end();
|
|
return iter;
|
|
}
|
|
|
|
private:
|
|
TLS Internal;
|
|
T* Exemplar;
|
|
};
|
|
|
|
#endif
|
|
// VTK-HeaderTest-Exclude: vtkSMPThreadLocalObject.h
|