vtkSMPThreadLocal.h
Go to the documentation of this file.
1  /*=========================================================================
2 
3  Program: Visualization Toolkit
4  Module: vtkSMPThreadLocal.h
5 
6  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7  All rights reserved.
8  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10  This software is distributed WITHOUT ANY WARRANTY; without even
11  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  PURPOSE. See the above copyright notice for more information.
13 
14 =========================================================================*/
15 // .NAME vtkSMPThreadLocal - A simple thread local implementation for sequential operations.
16 // .SECTION Description
17 // A thread local object is one that maintains a copy of an object of the
18 // template type for each thread that processes data. vtkSMPThreadLocal
19 // creates storage for all threads but the actual objects are created
20 // the first time Local() is called. Note that some of the vtkSMPThreadLocal
21 // API is not thread safe. It can be safely used in a multi-threaded
22 // environment because Local() returns storage specific to a particular
23 // thread, which by default will be accessed sequentially. It is also
24 // thread-safe to iterate over vtkSMPThreadLocal as long as each thread
25 // creates its own iterator and does not change any of the thread local
26 // objects.
27 //
28 // A common design pattern in using a thread local storage object is to
29 // write/accumulate data to local object when executing in parallel and
30 // then having a sequential code block that iterates over the whole storage
31 // using the iterators to do the final accumulation.
32 //
33 // Note that this particular implementation is designed to work in sequential
34 // mode and supports only 1 thread.
35 
36 #ifndef vtkSMPThreadLocal_h
37 #define vtkSMPThreadLocal_h
38 
39 #include "vtkSystemIncludes.h"
40 
41 #include <iterator>
42 #include <vector>
43 
44 template <typename T>
46 {
47  typedef std::vector<T> TLS;
48  typedef typename TLS::iterator TLSIter;
49 public:
50  // Description:
51  // Default constructor. Creates a default exemplar.
52  vtkSMPThreadLocal() : NumInitialized(0)
53  {
54  this->Initialize();
55  }
56 
57  // Description:
58  // Constructor that allows the specification of an exemplar object
59  // which is used when constructing objects when Local() is first called.
60  // Note that a copy of the exemplar is created using its copy constructor.
61  explicit vtkSMPThreadLocal(const T& exemplar)
62  : NumInitialized(0), Exemplar(exemplar)
63  {
64  this->Initialize();
65  }
66 
67  // Description:
68  // Returns an object of type T that is local to the current thread.
69  // This needs to be called mainly within a threaded execution path.
70  // It will create a new object (local to the thread so each thread
71  // get their own when calling Local) which is a copy of exemplar as passed
72  // to the constructor (or a default object if no exemplar was provided)
73  // the first time it is called. After the first time, it will return
74  // the same object.
75  T& Local()
76  {
77  int tid = this->GetThreadID();
78  if (!this->Initialized[tid])
79  {
80  this->Internal[tid] = this->Exemplar;
81  this->Initialized[tid] = true;
82  ++this->NumInitialized;
83  }
84  return this->Internal[tid];
85  }
86 
87  // Description:
88  // Return the number of thread local objects that have been initialized
89  size_t size() const
90  {
91  return this->NumInitialized;
92  }
93 
94  // Description:
95  // Subset of the standard iterator API.
96  // The most common design pattern is to use iterators in a sequential
97  // code block and to use only the thread local objects in parallel
98  // code blocks.
99  // It is thread safe to iterate over the thread local containers
100  // as long as each thread uses its own iterator and does not modify
101  // objects in the container.
102  class iterator
103  : public std::iterator<std::forward_iterator_tag, T> // for iterator_traits
104  {
105  public:
107  {
108  this->InitIter++;
109  this->Iter++;
110 
111  // Make sure to skip uninitialized
112  // entries.
113  while(this->InitIter != this->EndIter)
114  {
115  if (*this->InitIter)
116  {
117  break;
118  }
119  this->InitIter++;
120  this->Iter++;
121  }
122  return *this;
123  }
124 
126  {
127  iterator copy = *this;
128  ++(*this);
129  return copy;
130  }
131 
132  bool operator==(const iterator& other)
133  {
134  return this->Iter == other.Iter;
135  }
136 
137  bool operator!=(const iterator& other)
138  {
139  return this->Iter != other.Iter;
140  }
141 
143  {
144  return *this->Iter;
145  }
146 
148  {
149  return &*this->Iter;
150  }
151 
152  private:
153  friend class vtkSMPThreadLocal<T>;
154  std::vector<bool>::iterator InitIter;
155  std::vector<bool>::iterator EndIter;
156  TLSIter Iter;
157  };
158 
159  // Description:
160  // Returns a new iterator pointing to the beginning of
161  // the local storage container. Thread safe.
162  iterator begin()
163  {
164  TLSIter iter = this->Internal.begin();
165  std::vector<bool>::iterator iter2 =
166  this->Initialized.begin();
167  std::vector<bool>::iterator enditer =
168  this->Initialized.end();
169  // fast forward to first initialized
170  // value
171  while(iter2 != enditer)
172  {
173  if (*iter2)
174  {
175  break;
176  }
177  iter2++;
178  iter++;
179  }
180  iterator retVal;
181  retVal.InitIter = iter2;
182  retVal.EndIter = enditer;
183  retVal.Iter = iter;
184  return retVal;
185  };
186 
187  // Description:
188  // Returns a new iterator pointing to past the end of
189  // the local storage container. Thread safe.
190  iterator end()
191  {
192  iterator retVal;
193  retVal.InitIter = this->Initialized.end();
194  retVal.EndIter = this->Initialized.end();
195  retVal.Iter = this->Internal.end();
196  return retVal;
197  }
198 
199 private:
200  TLS Internal;
201  std::vector<bool> Initialized;
202  size_t NumInitialized;
203  T Exemplar;
204 
205  void Initialize()
206  {
207  this->Internal.resize(this->GetNumberOfThreads());
208  this->Initialized.resize(this->GetNumberOfThreads());
209  std::fill(this->Initialized.begin(),
210  this->Initialized.end(),
211  false);
212  }
213 
214  inline int GetNumberOfThreads()
215  {
216  return 1;
217  }
218 
219  inline int GetThreadID()
220  {
221  return 0;
222  }
223 
224  // disable copying
226  void operator=(const vtkSMPThreadLocal&);
227 };
228 #endif
229 // VTK-HeaderTest-Exclude: vtkSMPThreadLocal.h
vtkSMPThreadLocal(const T &exemplar)
bool operator!=(const iterator &other)
bool operator==(const iterator &other)
size_t size() const