/*========================================================================= 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. =========================================================================*/ // .NAME vtkSMPThreadLocal - A thread local storage implementation using // platform specific facilities. // .SECTION Description // 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. #ifndef vtkSMPThreadLocal_h #define vtkSMPThreadLocal_h #include "vtkSMPThreadLocalImpl.h" #include "vtkSMPToolsInternal.h" template class vtkSMPThreadLocal { public: // Description: // Default constructor. Creates a default exemplar. vtkSMPThreadLocal() : Backend(vtk::detail::smp::GetNumberOfThreads()) { } // Description: // 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) : Backend(vtk::detail::smp::GetNumberOfThreads()), Exemplar(exemplar) { } ~vtkSMPThreadLocal() { detail::ThreadSpecificStorageIterator it; it.SetThreadSpecificStorage(Backend); for (it.SetToBegin(); !it.GetAtEnd(); it.Forward()) { delete reinterpret_cast(it.GetStorage()); } } // Description: // Returns an object of type T that is local to the current thread. // This needs to be called mainly within a threaded execution path. // It will create a new object (local to the tread 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() { detail::StoragePointerType &ptr = this->Backend.GetStorage(); T *local = reinterpret_cast(ptr); if (!ptr) { ptr = local = new T(this->Exemplar); } return *local; } // Description: // Return the number of thread local objects that have been initialized size_t size() const { return this->Backend.Size(); } // Description: // 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. class iterator { public: iterator& operator++() { this->Impl.Forward(); return *this; } iterator operator++(int) { iterator copy = *this; this->Impl.Forward(); return copy; } bool operator==(const iterator& other) { return this->Impl == other.Impl; } bool operator!=(const iterator& other) { return !(this->Impl == other.Impl); } T& operator*() { return *reinterpret_cast(this->Impl.GetStorage()); } T* operator->() { return reinterpret_cast(this->Impl.GetStorage()); } private: detail::ThreadSpecificStorageIterator Impl; friend class vtkSMPThreadLocal; }; // Description: // Returns a new iterator pointing to the beginning of // the local storage container. Thread safe. iterator begin() { iterator it; it.Impl.SetThreadSpecificStorage(Backend); it.Impl.SetToBegin(); return it; } // Description: // Returns a new iterator pointing to past the end of // the local storage container. Thread safe. iterator end() { iterator it; it.Impl.SetThreadSpecificStorage(Backend); it.Impl.SetToEnd(); return it; } private: detail::ThreadSpecific Backend; T Exemplar; // disable copying vtkSMPThreadLocal(const vtkSMPThreadLocal&); void operator=(const vtkSMPThreadLocal&); }; #endif // VTK-HeaderTest-Exclude: vtkSMPThreadLocal.h