/*========================================================================= Program: Visualization Toolkit Module: vtkSMPThreadLocal.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 vtkSMPThreadLocal * @brief Thread local storage for VTK objects. * * A thread local object is one that maintains a copy of an object of the * template type for each thread that processes data. vtkSMPThreadLocal * creates storage for all threads but the actual objects are created * the first time Local() is called. Note that some of the vtkSMPThreadLocal * API is not thread safe. It can be safely used in a multi-threaded * environment because Local() returns storage specific to a particular * thread, which by default will be accessed sequentially. It is also * thread-safe to iterate over vtkSMPThreadLocal as long as each thread * creates its own iterator and does not change any of the thread local * objects. * * A common design pattern in using a thread local storage object is to * write/accumulate data to local object when executing in parallel and * then having a sequential code block that iterates over the whole storage * using the iterators to do the final accumulation. * * @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 * * @code * vtkSMPThreadLocal Foo; * vtkSMPThreadLocal Bar; * class AFunctor * { * void Initialize() const * { * int& foo = Foo.Local(); * int& bar = Bar.Local(); * foo = random(); * bar = foo; * } * * void operator()(vtkIdType, vtkIdType) const * {} * }; * * AFunctor functor; * vtkParalllelUtilities::For(0, 100000, functor); * * vtkSMPThreadLocal::iterator itr1 = Foo.begin(); * vtkSMPThreadLocal::iterator itr2 = Bar.begin(); * while (itr1 != Foo.end()) * { * assert(*itr1 == *itr2); * ++itr1; ++itr2; * } * @endcode * * @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 * vtkSMPThreadLocalObject */ #ifndef vtkSMPThreadLocal_h #define vtkSMPThreadLocal_h #include "SMP/Common/vtkSMPThreadLocalAPI.h" template class vtkSMPThreadLocal { public: /** * Default constructor. Creates a default exemplar. */ vtkSMPThreadLocal() : ThreadLocalAPI() { } /** * Constructor that allows the specification of an exemplar object * which is used when constructing objects when Local() is first called. * Note that a copy of the exemplar is created using its copy constructor. */ explicit vtkSMPThreadLocal(const T& exemplar) : ThreadLocalAPI(exemplar) { } /** * This needs to be called mainly within a threaded execution path. * It will create a new object (local to the thread so each thread * get their own when calling Local) which is a copy of exemplar as passed * to the constructor (or a default object if no exemplar was provided) * the first time it is called. After the first time, it will return * the same object. */ T& Local() { return this->ThreadLocalAPI.Local(); } /** * Return the number of thread local objects that have been initialized */ size_t size() { return this->ThreadLocalAPI.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. * It is thread safe to iterate over the thread local containers * as long as each thread uses its own iterator and does not modify * objects in the container. */ typedef typename vtk::detail::smp::vtkSMPThreadLocalAPI::iterator iterator; /** * Returns a new iterator pointing to the beginning of * the local storage container. Thread safe. */ iterator begin() { return this->ThreadLocalAPI.begin(); }; /** * Returns a new iterator pointing to past the end of * the local storage container. Thread safe. */ iterator end() { return this->ThreadLocalAPI.end(); } private: vtk::detail::smp::vtkSMPThreadLocalAPI ThreadLocalAPI; // disable copying vtkSMPThreadLocal(const vtkSMPThreadLocal&) = delete; void operator=(const vtkSMPThreadLocal&) = delete; }; #endif // VTK-HeaderTest-Exclude: vtkSMPThreadLocal.h