1 // Copyright (c) 2013-2014 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 #ifndef OSD_Parallel_HeaderFile
15 #define OSD_Parallel_HeaderFile
17 #include <OSD_ThreadPool.hxx>
18 #include <Standard_Type.hxx>
20 #include <type_traits>
22 //! @brief Simple tool for code parallelization.
24 //! OSD_Parallel class provides simple interface for parallel processing of
25 //! tasks that can be formulated in terms of "for" or "foreach" loops.
27 //! To use this tool it is necessary to:
28 //! - organize the data to be processed in a collection accessible by
29 //! iteration (usually array or vector);
30 //! - implement a functor class providing operator () accepting iterator
31 //! (or index in array) that does the job;
32 //! - call either For() or ForEach() providing begin and end iterators and
35 //! Iterators should satisfy requirements of STL forward iterator.
42 //! void operator() ([proccesing instance]) const
49 //! The operator () should be implemented in a thread-safe way so that
50 //! the same functor object can process different data items in parallel threads.
52 //! Iteration by index (For) is expected to be more efficient than using iterators
55 //! Implementation uses TBB if OCCT is built with support of TBB; otherwise it
56 //! uses ad-hoc parallelization tool. In general, if TBB is available, it is
57 //! more efficient to use it directly instead of using OSD_Parallel.
63 //! Interface class defining API for polymorphic wrappers over iterators.
64 //! Intended to add polymorphic behaviour to For and ForEach functionality
65 //! for arbitrary objects and eliminate dependency on template parameters.
66 class IteratorInterface
69 virtual ~IteratorInterface() {}
71 //! Returns true if iterators wrapped by this and theOther are equal
72 virtual bool IsEqual (const IteratorInterface& theOther) const = 0;
74 //! Increments wrapped iterator
75 virtual void Increment () = 0;
77 //! Returns new instance of the wrapper containing copy
78 //! of the wrapped iterator.
79 virtual IteratorInterface* Clone() const = 0;
82 //! Implementation of polymorphic iterator wrapper suitable for basic
83 //! types as well as for std iterators.
84 //! Wraps instance of actual iterator type Type.
86 class IteratorWrapper : public IteratorInterface
90 IteratorWrapper(const Type& theValue) : myValue(theValue) {}
92 virtual bool IsEqual (const IteratorInterface& theOther) const Standard_OVERRIDE
94 return myValue == dynamic_cast<const IteratorWrapper<Type>&>(theOther).myValue;
97 virtual void Increment () Standard_OVERRIDE
102 virtual IteratorInterface* Clone() const Standard_OVERRIDE
104 return new IteratorWrapper<Type>(myValue);
107 const Type& Value() const { return myValue; }
114 // Note: UniversalIterator and FunctorInterface are made protected to be
115 // accessible from specialization using threads (non-TBB).
117 //! Fixed-type iterator, implementing STL forward iterator interface, used for
118 //! iteration over objects subject to parallel processing.
119 //! It stores pointer to instance of polymorphic iterator inheriting from
120 //! IteratorInterface, which contains actual type-specific iterator.
121 class UniversalIterator :
122 // Note that TBB requires that value_type of iterator be copyable,
123 // thus we use its own type for that
124 public std::iterator<std::forward_iterator_tag, UniversalIterator, ptrdiff_t, UniversalIterator*, UniversalIterator&>
127 UniversalIterator() {}
129 UniversalIterator(IteratorInterface* theOther)
134 UniversalIterator(const UniversalIterator& theOther)
135 : myPtr (theOther.myPtr->Clone())
139 UniversalIterator& operator= (const UniversalIterator& theOther)
141 myPtr.reset (theOther.myPtr->Clone());
145 bool operator!= (const UniversalIterator& theOther) const
147 return ! myPtr->IsEqual (*theOther.myPtr);
150 bool operator== (const UniversalIterator& theOther) const
152 return myPtr->IsEqual (*theOther.myPtr);
155 UniversalIterator& operator++()
161 UniversalIterator operator++(int)
163 UniversalIterator aValue(*this);
168 const UniversalIterator& operator* () const { return *this; }
169 UniversalIterator& operator* () { return *this; }
171 const UniversalIterator* operator->() const { return this; }
172 UniversalIterator* operator->() { return this; }
174 // type cast to actual iterator
175 template <typename Iterator>
176 const Iterator& DownCast () const
178 return dynamic_cast<OSD_Parallel::IteratorWrapper<Iterator>*>(myPtr.get())->Value();
182 #if (defined(_MSC_VER) && (_MSC_VER < 1600))
183 std::auto_ptr<IteratorInterface> myPtr;
185 std::unique_ptr<IteratorInterface> myPtr;
189 //! Interface class representing functor object.
190 //! Intended to add polymorphic behavour to For and ForEach functionality
191 //! enabling execution of arbitrary function in parallel mode.
192 class FunctorInterface
195 virtual ~FunctorInterface() {}
197 virtual void operator () (UniversalIterator& theIterator) const = 0;
202 //! Wrapper for functors manipulating on std iterators.
203 template<class Iterator, class Functor>
204 class FunctorWrapperIter : public FunctorInterface
207 FunctorWrapperIter (const Functor& theFunctor)
208 : myFunctor(theFunctor)
212 virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
214 const Iterator& anIt = theIterator.DownCast<Iterator>();
219 FunctorWrapperIter (const FunctorWrapperIter&);
220 void operator = (const FunctorWrapperIter&);
221 const Functor& myFunctor;
224 //! Wrapper for functors manipulating on integer index.
225 template<class Functor>
226 class FunctorWrapperInt : public FunctorInterface
229 FunctorWrapperInt (const Functor& theFunctor)
230 : myFunctor(theFunctor)
234 virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
236 Standard_Integer anIndex = theIterator.DownCast<Standard_Integer>();
241 FunctorWrapperInt (const FunctorWrapperInt&);
242 void operator = (const FunctorWrapperInt&);
243 const Functor& myFunctor;
246 //! Wrapper redirecting functor taking element index to functor taking also thread index.
247 template<class Functor>
248 class FunctorWrapperForThreadPool
251 FunctorWrapperForThreadPool (const Functor& theFunctor) : myFunctor(theFunctor) {}
253 void operator() (int theThreadIndex, int theElemIndex) const
255 (void )theThreadIndex;
256 myFunctor (theElemIndex);
259 FunctorWrapperForThreadPool (const FunctorWrapperForThreadPool&);
260 void operator= (const FunctorWrapperForThreadPool&);
261 const Functor& myFunctor;
266 //! Simple primitive for parallelization of "foreach" loops, e.g.:
268 //! for (std::iterator anIter = theBegin; anIter != theEnd; ++anIter) {}
270 //! Implementation of framework-dependent functionality should be provided by
271 //! forEach_impl function defined in opencascade::parallel namespace.
272 //! @param theBegin the first index (inclusive)
273 //! @param theEnd the last index (exclusive)
274 //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
275 //! performing task for the specified iterator position
276 //! @param theNbItems number of items passed by iterator, -1 if unknown
277 Standard_EXPORT static void forEachOcct (UniversalIterator& theBegin,
278 UniversalIterator& theEnd,
279 const FunctorInterface& theFunctor,
280 Standard_Integer theNbItems);
282 //! Same as forEachOcct() but can be implemented using external threads library.
283 Standard_EXPORT static void forEachExternal (UniversalIterator& theBegin,
284 UniversalIterator& theEnd,
285 const FunctorInterface& theFunctor,
286 Standard_Integer theNbItems);
288 public: //! @name public methods
290 //! Returns TRUE if OCCT threads should be used instead of auxiliary threads library;
291 //! default value is FALSE if alternative library has been enabled while OCCT building and TRUE otherwise.
292 Standard_EXPORT static Standard_Boolean ToUseOcctThreads();
294 //! Sets if OCCT threads should be used instead of auxiliary threads library.
295 //! Has no effect if OCCT has been built with no auxiliary threads library.
296 Standard_EXPORT static void SetUseOcctThreads (Standard_Boolean theToUseOcct);
298 //! Returns number of logical processors.
299 Standard_EXPORT static Standard_Integer NbLogicalProcessors();
301 //! Simple primitive for parallelization of "foreach" loops, equivalent to:
303 //! for (auto anIter = theBegin; anIter != theEnd; ++anIter) {
304 //! theFunctor(*anIter);
307 //! @param theBegin the first index (inclusive)
308 //! @param theEnd the last index (exclusive)
309 //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
310 //! performing task for specified iterator position
311 //! @param isForceSingleThreadExecution if true, then no threads will be created
312 //! @param theNbItems number of items passed by iterator, -1 if unknown
313 template <typename InputIterator, typename Functor>
314 static void ForEach(InputIterator theBegin,
315 InputIterator theEnd,
316 const Functor& theFunctor,
317 const Standard_Boolean isForceSingleThreadExecution = Standard_False,
318 Standard_Integer theNbItems = -1)
320 if (isForceSingleThreadExecution || theNbItems == 1)
322 for (InputIterator it(theBegin); it != theEnd; ++it)
327 UniversalIterator aBegin(new IteratorWrapper<InputIterator>(theBegin));
328 UniversalIterator aEnd (new IteratorWrapper<InputIterator>(theEnd));
329 FunctorWrapperIter<InputIterator,Functor> aFunctor (theFunctor);
330 if (ToUseOcctThreads())
332 forEachOcct (aBegin, aEnd, aFunctor, theNbItems);
336 forEachExternal (aBegin, aEnd, aFunctor, theNbItems);
341 //! Simple primitive for parallelization of "for" loops, equivalent to:
343 //! for (int anIter = theBegin; anIter != theEnd; ++anIter) {
344 //! theFunctor(anIter);
347 //! @param theBegin the first index (inclusive)
348 //! @param theEnd the last index (exclusive)
349 //! @param theFunctor functor providing an interface "void operator(int theIndex){}"
350 //! performing task for specified index
351 //! @param isForceSingleThreadExecution if true, then no threads will be created
352 template <typename Functor>
353 static void For(const Standard_Integer theBegin,
354 const Standard_Integer theEnd,
355 const Functor& theFunctor,
356 const Standard_Boolean isForceSingleThreadExecution = Standard_False)
358 const Standard_Integer aRange = theEnd - theBegin;
359 if (isForceSingleThreadExecution || aRange == 1)
361 for (Standard_Integer it (theBegin); it != theEnd; ++it)
364 else if (ToUseOcctThreads())
366 const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
367 OSD_ThreadPool::Launcher aPoolLauncher (*aThreadPool, aRange);
368 FunctorWrapperForThreadPool<Functor> aFunctor (theFunctor);
369 aPoolLauncher.Perform (theBegin, theEnd, aFunctor);
373 UniversalIterator aBegin(new IteratorWrapper<Standard_Integer>(theBegin));
374 UniversalIterator aEnd (new IteratorWrapper<Standard_Integer>(theEnd));
375 FunctorWrapperInt<Functor> aFunctor (theFunctor);
376 forEachExternal (aBegin, aEnd, aFunctor, aRange);