Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-12 09:18:25

0001 // Copyright (c) 2013-2014 OPEN CASCADE SAS
0002 //
0003 // This file is part of Open CASCADE Technology software library.
0004 //
0005 // This library is free software; you can redistribute it and/or modify it under
0006 // the terms of the GNU Lesser General Public License version 2.1 as published
0007 // by the Free Software Foundation, with special exception defined in the file
0008 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0009 // distribution for complete text of the license and disclaimer of any warranty.
0010 //
0011 // Alternatively, this file may be used under the terms of Open CASCADE
0012 // commercial license or contractual agreement.
0013 
0014 #ifndef OSD_Parallel_HeaderFile
0015 #define OSD_Parallel_HeaderFile
0016 
0017 #include <OSD_ThreadPool.hxx>
0018 #include <Standard_Type.hxx>
0019 #include <memory>
0020 
0021 //! @brief Simple tool for code parallelization.
0022 //!
0023 //! OSD_Parallel class provides simple interface for parallel processing of
0024 //! tasks that can be formulated in terms of "for" or "foreach" loops.
0025 //!
0026 //! To use this tool it is necessary to:
0027 //! - organize the data to be processed in a collection accessible by
0028 //!   iteration (usually array or vector);
0029 //! - implement a functor class providing operator () accepting iterator
0030 //!   (or index in array) that does the job;
0031 //! - call either For() or ForEach() providing begin and end iterators and
0032 //!   a functor object.
0033 //!
0034 //! Iterators should satisfy requirements of STL forward iterator.
0035 //! Functor
0036 //!
0037 //! @code
0038 //! class Functor
0039 //! {
0040 //! public:
0041 //!   void operator() ([processing instance]) const
0042 //!   {
0043 //!     //...
0044 //!   }
0045 //! };
0046 //! @endcode
0047 //!
0048 //! The operator () should be implemented in a thread-safe way so that
0049 //! the same functor object can process different data items in parallel threads.
0050 //!
0051 //! Iteration by index (For) is expected to be more efficient than using iterators
0052 //! (ForEach).
0053 //!
0054 //! Implementation uses TBB if OCCT is built with support of TBB; otherwise it
0055 //! uses ad-hoc parallelization tool. In general, if TBB is available, it is
0056 //! more efficient to use it directly instead of using OSD_Parallel.
0057 
0058 class OSD_Parallel
0059 {
0060 private:
0061   //! Interface class defining API for polymorphic wrappers over iterators.
0062   //! Intended to add polymorphic behaviour to For and ForEach functionality
0063   //! for arbitrary objects and eliminate dependency on template parameters.
0064   class IteratorInterface
0065   {
0066   public:
0067     virtual ~IteratorInterface() = default;
0068 
0069     //! Returns true if iterators wrapped by this and theOther are equal
0070     virtual bool IsEqual(const IteratorInterface& theOther) const = 0;
0071 
0072     //! Increments wrapped iterator
0073     virtual void Increment() = 0;
0074 
0075     //! Returns new instance of the wrapper containing copy
0076     //! of the wrapped iterator.
0077     virtual IteratorInterface* Clone() const = 0;
0078   };
0079 
0080   //! Implementation of polymorphic iterator wrapper suitable for basic
0081   //! types as well as for std iterators.
0082   //! Wraps instance of actual iterator type Type.
0083   template <class Type>
0084   class IteratorWrapper : public IteratorInterface
0085   {
0086   public:
0087     IteratorWrapper() = default;
0088 
0089     IteratorWrapper(const Type& theValue)
0090         : myValue(theValue)
0091     {
0092     }
0093 
0094     bool IsEqual(const IteratorInterface& theOther) const override
0095     {
0096       return myValue == dynamic_cast<const IteratorWrapper<Type>&>(theOther).myValue;
0097     }
0098 
0099     void Increment() override { ++myValue; }
0100 
0101     IteratorInterface* Clone() const override { return new IteratorWrapper<Type>(myValue); }
0102 
0103     const Type& Value() const { return myValue; }
0104 
0105   private:
0106     Type myValue;
0107   };
0108 
0109 protected:
0110   // Note: UniversalIterator and FunctorInterface are made protected to be
0111   // accessible from specialization using threads (non-TBB).
0112 
0113   //! Fixed-type iterator, implementing STL forward iterator interface, used for
0114   //! iteration over objects subject to parallel processing.
0115   //! It stores pointer to instance of polymorphic iterator inheriting from
0116   //! IteratorInterface, which contains actual type-specific iterator.
0117   class UniversalIterator
0118   // Note that TBB requires that value_type of iterator be copyable,
0119   // thus we use its own type for that
0120   {
0121   public:
0122     // Since C++20 inheritance from std::iterator is deprecated, so define predefined types
0123     // manually:
0124     using iterator_category = std::forward_iterator_tag;
0125     using value_type        = IteratorInterface*;
0126     using difference_type   = ptrdiff_t;
0127     using pointer           = value_type;
0128     using reference         = value_type;
0129 
0130     UniversalIterator() = default;
0131 
0132     UniversalIterator(IteratorInterface* theOther)
0133         : myPtr(theOther)
0134     {
0135     }
0136 
0137     UniversalIterator(const UniversalIterator& theOther)
0138         : myPtr(theOther.myPtr->Clone())
0139     {
0140     }
0141 
0142     UniversalIterator& operator=(const UniversalIterator& theOther)
0143     {
0144       myPtr.reset(theOther.myPtr->Clone());
0145       return *this;
0146     }
0147 
0148     bool operator!=(const UniversalIterator& theOther) const
0149     {
0150       return !myPtr->IsEqual(*theOther.myPtr);
0151     }
0152 
0153     bool operator==(const UniversalIterator& theOther) const
0154     {
0155       return myPtr->IsEqual(*theOther.myPtr);
0156     }
0157 
0158     UniversalIterator& operator++()
0159     {
0160       myPtr->Increment();
0161       return *this;
0162     }
0163 
0164     UniversalIterator operator++(int)
0165     {
0166       UniversalIterator aValue(*this);
0167       myPtr->Increment();
0168       return aValue;
0169     }
0170 
0171     reference operator*() const { return myPtr.get(); }
0172 
0173     reference operator*() { return myPtr.get(); }
0174 
0175   private:
0176     std::unique_ptr<IteratorInterface> myPtr;
0177   };
0178 
0179   //! Interface class representing functor object.
0180   //! Intended to add polymorphic behaviour to For and ForEach functionality
0181   //! enabling execution of arbitrary function in parallel mode.
0182   class FunctorInterface
0183   {
0184   public:
0185     virtual ~FunctorInterface() = default;
0186 
0187     virtual void operator()(IteratorInterface* theIterator) const = 0;
0188 
0189     // type cast to actual iterator
0190     template <typename Iterator>
0191     static const Iterator& DownCast(IteratorInterface* theIterator)
0192     {
0193       return dynamic_cast<OSD_Parallel::IteratorWrapper<Iterator>*>(theIterator)->Value();
0194     }
0195   };
0196 
0197 private:
0198   //! Wrapper for functors manipulating on std iterators.
0199   template <class Iterator, class Functor>
0200   class FunctorWrapperIter : public FunctorInterface
0201   {
0202   public:
0203     FunctorWrapperIter(const Functor& theFunctor)
0204         : myFunctor(theFunctor)
0205     {
0206     }
0207 
0208     void operator()(IteratorInterface* theIterator) const override
0209     {
0210       const Iterator& anIt = DownCast<Iterator>(theIterator);
0211       myFunctor(*anIt);
0212     }
0213 
0214   private:
0215     FunctorWrapperIter(const FunctorWrapperIter&)       = delete;
0216     void           operator=(const FunctorWrapperIter&) = delete;
0217     const Functor& myFunctor;
0218   };
0219 
0220   //! Wrapper for functors manipulating on integer index.
0221   template <class Functor>
0222   class FunctorWrapperInt : public FunctorInterface
0223   {
0224   public:
0225     FunctorWrapperInt(const Functor& theFunctor)
0226         : myFunctor(theFunctor)
0227     {
0228     }
0229 
0230     void operator()(IteratorInterface* theIterator) const override
0231     {
0232       int anIndex = DownCast<int>(theIterator);
0233       myFunctor(anIndex);
0234     }
0235 
0236   private:
0237     FunctorWrapperInt(const FunctorWrapperInt&)        = delete;
0238     void           operator=(const FunctorWrapperInt&) = delete;
0239     const Functor& myFunctor;
0240   };
0241 
0242   //! Wrapper redirecting functor taking element index to functor taking also thread index.
0243   template <class Functor>
0244   class FunctorWrapperForThreadPool
0245   {
0246   public:
0247     FunctorWrapperForThreadPool(const Functor& theFunctor)
0248         : myFunctor(theFunctor)
0249     {
0250     }
0251 
0252     void operator()(int theThreadIndex, int theElemIndex) const
0253     {
0254       (void)theThreadIndex;
0255       myFunctor(theElemIndex);
0256     }
0257 
0258   private:
0259     FunctorWrapperForThreadPool(const FunctorWrapperForThreadPool&) = delete;
0260     void           operator=(const FunctorWrapperForThreadPool&)    = delete;
0261     const Functor& myFunctor;
0262   };
0263 
0264 private:
0265   //! Simple primitive for parallelization of "foreach" loops, e.g.:
0266   //! @code
0267   //!   for (std::iterator anIter = theBegin; anIter != theEnd; ++anIter) {}
0268   //! @endcode
0269   //! Implementation of framework-dependent functionality should be provided by
0270   //! forEach_impl function defined in opencascade::parallel namespace.
0271   //! @param theBegin   the first index (inclusive)
0272   //! @param theEnd     the last  index (exclusive)
0273   //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
0274   //!                   performing task for the specified iterator position
0275   //! @param theNbItems number of items passed by iterator, -1 if unknown
0276   Standard_EXPORT static void forEachOcct(UniversalIterator&      theBegin,
0277                                           UniversalIterator&      theEnd,
0278                                           const FunctorInterface& theFunctor,
0279                                           int                     theNbItems);
0280 
0281   //! Same as forEachOcct() but can be implemented using external threads library.
0282   Standard_EXPORT static void forEachExternal(UniversalIterator&      theBegin,
0283                                               UniversalIterator&      theEnd,
0284                                               const FunctorInterface& theFunctor,
0285                                               int                     theNbItems);
0286 
0287 public: //! @name public methods
0288   //! Returns TRUE if OCCT threads should be used instead of auxiliary threads library;
0289   //! default value is FALSE if alternative library has been enabled while OCCT building and TRUE
0290   //! otherwise.
0291   Standard_EXPORT static bool ToUseOcctThreads();
0292 
0293   //! Sets if OCCT threads should be used instead of auxiliary threads library.
0294   //! Has no effect if OCCT has been built with no auxiliary threads library.
0295   Standard_EXPORT static void SetUseOcctThreads(bool theToUseOcct);
0296 
0297   //! Returns number of logical processors.
0298   Standard_EXPORT static int NbLogicalProcessors();
0299 
0300   //! Simple primitive for parallelization of "foreach" loops, equivalent to:
0301   //! @code
0302   //!   for (auto anIter = theBegin; anIter != theEnd; ++anIter) {
0303   //!     theFunctor(*anIter);
0304   //!   }
0305   //! @endcode
0306   //! @param theBegin   the first index (inclusive)
0307   //! @param theEnd     the last  index (exclusive)
0308   //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
0309   //!                   performing task for specified iterator position
0310   //! @param isForceSingleThreadExecution if true, then no threads will be created
0311   //! @param theNbItems number of items passed by iterator, -1 if unknown
0312   template <typename InputIterator, typename Functor>
0313   static void ForEach(InputIterator  theBegin,
0314                       InputIterator  theEnd,
0315                       const Functor& theFunctor,
0316                       const bool     isForceSingleThreadExecution = false,
0317                       int            theNbItems                   = -1)
0318   {
0319     if (isForceSingleThreadExecution || theNbItems == 1)
0320     {
0321       for (InputIterator it(theBegin); it != theEnd; ++it)
0322         theFunctor(*it);
0323     }
0324     else
0325     {
0326       UniversalIterator aBegin(new IteratorWrapper<InputIterator>(theBegin));
0327       UniversalIterator aEnd(new IteratorWrapper<InputIterator>(theEnd));
0328       FunctorWrapperIter<InputIterator, Functor> aFunctor(theFunctor);
0329       if (ToUseOcctThreads())
0330       {
0331         forEachOcct(aBegin, aEnd, aFunctor, theNbItems);
0332       }
0333       else
0334       {
0335         forEachExternal(aBegin, aEnd, aFunctor, theNbItems);
0336       }
0337     }
0338   }
0339 
0340   //! Simple primitive for parallelization of "for" loops, equivalent to:
0341   //! @code
0342   //!   for (int anIter = theBegin; anIter != theEnd; ++anIter) {
0343   //!     theFunctor(anIter);
0344   //!   }
0345   //! @endcode
0346   //! @param theBegin   the first index (inclusive)
0347   //! @param theEnd     the last  index (exclusive)
0348   //! @param theFunctor functor providing an interface "void operator(int theIndex){}"
0349   //!                   performing task for specified index
0350   //! @param isForceSingleThreadExecution if true, then no threads will be created
0351   template <typename Functor>
0352   static void For(const int      theBegin,
0353                   const int      theEnd,
0354                   const Functor& theFunctor,
0355                   const bool     isForceSingleThreadExecution = false)
0356   {
0357     const int aRange = theEnd - theBegin;
0358     if (isForceSingleThreadExecution || aRange == 1)
0359     {
0360       for (int it(theBegin); it != theEnd; ++it)
0361         theFunctor(it);
0362     }
0363     else if (ToUseOcctThreads())
0364     {
0365       const occ::handle<OSD_ThreadPool>&   aThreadPool = OSD_ThreadPool::DefaultPool();
0366       OSD_ThreadPool::Launcher             aPoolLauncher(*aThreadPool, aRange);
0367       FunctorWrapperForThreadPool<Functor> aFunctor(theFunctor);
0368       aPoolLauncher.Perform(theBegin, theEnd, aFunctor);
0369     }
0370     else
0371     {
0372       UniversalIterator          aBegin(new IteratorWrapper<int>(theBegin));
0373       UniversalIterator          aEnd(new IteratorWrapper<int>(theEnd));
0374       FunctorWrapperInt<Functor> aFunctor(theFunctor);
0375       forEachExternal(aBegin, aEnd, aFunctor, aRange);
0376     }
0377   }
0378 };
0379 
0380 #endif