VTK
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 <vector>
42 
43 template <typename T>
45 {
46  typedef std::vector<T> TLS;
47  typedef typename TLS::iterator TLSIter;
48 public:
49  // Description:
50  // Default constructor. Creates a default exemplar.
51  vtkSMPThreadLocal() : NumInitialized(0)
52  {
53  this->Initialize();
54  }
55 
56  // Description:
57  // Constructor that allows the specification of an exemplar object
58  // which is used when constructing objects when Local() is first called.
59  // Note that a copy of the exemplar is created using its copy constructor.
60  explicit vtkSMPThreadLocal(const T& exemplar)
61  : NumInitialized(0), Exemplar(exemplar)
62  {
63  this->Initialize();
64  }
65 
66  // Description:
67  // Returns an object of type T that is local to the current thread.
68  // This needs to be called mainly within a threaded execution path.
69  // It will create a new object (local to the tread so each thread
70  // get their own when calling Local) which is a copy of exemplar as passed
71  // to the constructor (or a default object if no exemplar was provided)
72  // the first time it is called. After the first time, it will return
73  // the same object.
74  T& Local()
75  {
76  int tid = this->GetThreadID();
77  if (!this->Initialized[tid])
78  {
79  this->Internal[tid] = this->Exemplar;
80  this->Initialized[tid] = true;
81  ++this->NumInitialized;
82  }
83  return this->Internal[tid];
84  }
85 
86  // Description:
87  // Return the number of thread local objects that have been initialized
88  size_t size() const
89  {
90  return this->NumInitialized;
91  }
92 
93  // Description:
94  // Subset of the standard iterator API.
95  // The most common design pattern is to use iterators in a sequential
96  // code block and to use only the thread local objects in parallel
97  // code blocks.
98  // It is thread safe to iterate over the thread local containers
99  // as long as each thread uses its own iterator and does not modify
100  // objects in the container.
101  class iterator
102  {
103  public:
105  {
106  this->InitIter++;
107  this->Iter++;
108 
109  // Make sure to skip uninitialized
110  // entries.
111  while(this->InitIter != this->EndIter)
112  {
113  if (*this->InitIter)
114  {
115  break;
116  }
117  this->InitIter++;
118  this->Iter++;
119  }
120  return *this;
121  }
122 
124  {
125  iterator copy = *this;
126  ++(*this);
127  return copy;
128  }
129 
130  bool operator==(const iterator& other)
131  {
132  return this->Iter == other.Iter;
133  }
134 
135  bool operator!=(const iterator& other)
136  {
137  return this->Iter != other.Iter;
138  }
139 
141  {
142  return *this->Iter;
143  }
144 
146  {
147  return &*this->Iter;
148  }
149 
150  private:
151  friend class vtkSMPThreadLocal<T>;
152  std::vector<bool>::iterator InitIter;
153  std::vector<bool>::iterator EndIter;
154  TLSIter Iter;
155  };
156 
157  // Description:
158  // Returns a new iterator pointing to the beginning of
159  // the local storage container. Thread safe.
160  iterator begin()
161  {
162  TLSIter iter = this->Internal.begin();
163  std::vector<bool>::iterator iter2 =
164  this->Initialized.begin();
165  std::vector<bool>::iterator enditer =
166  this->Initialized.end();
167  // fast forward to first initialized
168  // value
169  while(iter2 != enditer)
170  {
171  if (*iter2)
172  {
173  break;
174  }
175  iter2++;
176  iter++;
177  }
178  iterator retVal;
179  retVal.InitIter = iter2;
180  retVal.EndIter = enditer;
181  retVal.Iter = iter;
182  return retVal;
183  };
184 
185  // Description:
186  // Returns a new iterator pointing to past the end of
187  // the local storage container. Thread safe.
188  iterator end()
189  {
190  iterator retVal;
191  retVal.InitIter = this->Initialized.end();
192  retVal.EndIter = this->Initialized.end();
193  retVal.Iter = this->Internal.end();
194  return retVal;
195  }
196 
197 private:
198  TLS Internal;
199  std::vector<bool> Initialized;
200  size_t NumInitialized;
201  T Exemplar;
202 
203  void Initialize()
204  {
205  this->Internal.resize(this->GetNumberOfThreads());
206  this->Initialized.resize(this->GetNumberOfThreads());
207  std::fill(this->Initialized.begin(),
208  this->Initialized.end(),
209  false);
210  }
211 
212  inline int GetNumberOfThreads()
213  {
214  return 1;
215  }
216 
217  inline int GetThreadID()
218  {
219  return 0;
220  }
221 
222  // disable copying
224  void operator=(const vtkSMPThreadLocal&);
225 };
226 #endif
227 // VTK-HeaderTest-Exclude: vtkSMPThreadLocal.h
vtkSMPThreadLocal(const T &exemplar)
bool operator!=(const iterator &other)
bool operator==(const iterator &other)
size_t size() const