0030618: Modeling Algorithms, BOPTools_Parallel - avoid using map for thread-local...
[occt.git] / src / BOPTools / BOPTools_Parallel.hxx
index 0fddce5..58e121b 100644 (file)
 #include <Standard_Macro.hxx>
 #include <Standard_NotImplemented.hxx>
 #include <OSD_Parallel.hxx>
+#include <OSD_ThreadPool.hxx>
 #include <NCollection_DataMap.hxx>
 #include <Standard_Mutex.hxx>
 #include <OSD_Thread.hxx>
 
-//
-// 1. Implementation of Functors/Starters
-//
-// 1.1. Pure version
-//
-
-//=======================================================================
-//class    : BOPTools_Functor
-//purpose  : 
-//=======================================================================
-template <class TypeSolver, class TypeSolverVector>
-class BOPTools_Functor
+//! Implementation of Functors/Starters
+class BOPTools_Parallel
 {
-public:
-  //! Constructor.
-  explicit BOPTools_Functor(TypeSolverVector& theSolverVec) 
-  : mySolvers(theSolverVec) {}
-
-  //! Defines functor interface.
-  void operator() (const Standard_Integer theIndex) const
+  template<class TypeSolverVector>
+  class Functor
   {
-    TypeSolver& aSolver = mySolvers(theIndex);
-    aSolver.Perform();
-  }
-
-private:
-  BOPTools_Functor(const BOPTools_Functor&);
-  BOPTools_Functor& operator= (const BOPTools_Functor&);
+  public:
+    //! Constructor.
+    explicit Functor(TypeSolverVector& theSolverVec) : mySolvers (theSolverVec) {}
 
-private:
-  TypeSolverVector& mySolvers;
-};
+    //! Defines functor interface.
+    void operator() (const Standard_Integer theIndex) const
+    {
+      typename TypeSolverVector::value_type& aSolver = mySolvers[theIndex];
+      aSolver.Perform();
+    }
 
-//=======================================================================
-//class    : BOPTools_Cnt
-//purpose  : 
-//=======================================================================
-template <class TypeFunctor, class TypeSolverVector>
-class BOPTools_Cnt
-{
-public:
-  static void Perform( const Standard_Boolean isRunParallel,
-                       TypeSolverVector&      theSolverVector )
-  {
-    TypeFunctor aFunctor(theSolverVector);
-    OSD_Parallel::For(0, theSolverVector.Length(), aFunctor, !isRunParallel);
-  }
-};
+  private:
+    Functor(const Functor&);
+    Functor& operator= (const Functor&);
 
-//
-// 1.2. Context dependent version
-//
+  private:
+    TypeSolverVector& mySolvers;
+  };
 
-//=======================================================================
-//class    : BOPTools_ContextFunctor
-//purpose  : 
-//=======================================================================
-template <class TypeSolver,  class TypeSolverVector,
-          class TypeContext, typename TN>
-class BOPTools_ContextFunctor
-{
-  //! Auxiliary thread ID  hasher.
-  struct Hasher
+  //! Functor storing map of thread id -> algorithm context
+  template<class TypeSolverVector, class TypeContext>
+  class ContextFunctor
   {
-    static Standard_Integer HashCode(const Standard_ThreadId theKey,
-                                     const Standard_Integer  Upper)
+    //! Auxiliary thread ID  hasher.
+    struct Hasher
+    {
+      static Standard_Integer HashCode(const Standard_ThreadId theKey,
+                                       const Standard_Integer  Upper)
+      {
+        return ::HashCode((Standard_Size)theKey, Upper);
+      }
+
+      static Standard_Boolean IsEqual(const Standard_ThreadId theKey1,
+                                      const Standard_ThreadId theKey2)
+      {
+        return theKey1 == theKey2;
+      }
+    };
+
+  public:
+
+    //! Constructor
+    explicit ContextFunctor (TypeSolverVector& theVector) : mySolverVector(theVector) {}
+
+    //! Binds main thread context
+    void SetContext (const opencascade::handle<TypeContext>& theContext)
     {
-      return ::HashCode((Standard_Size)theKey, Upper);
+      myContextMap.Bind (OSD_Thread::Current(), theContext);
     }
 
-    static Standard_Boolean IsEqual(const Standard_ThreadId theKey1,
-                                    const Standard_ThreadId theKey2)
+    //! Returns current thread context
+    const opencascade::handle<TypeContext>& GetThreadContext() const
     {
-      return theKey1 == theKey2;
+      const Standard_ThreadId aThreadID = OSD_Thread::Current();
+      if (const opencascade::handle<TypeContext>* aContextPtr = myContextMap.Seek (aThreadID))
+      {
+        if (!aContextPtr->IsNull())
+        {
+          return *aContextPtr;
+        }
+      }
+
+      // Create new context
+      opencascade::handle<TypeContext> aContext = new TypeContext (NCollection_BaseAllocator::CommonBaseAllocator());
+
+      Standard_Mutex::Sentry aLocker (myMutex);
+      myContextMap.Bind (aThreadID, aContext);
+      return myContextMap (aThreadID);
     }
-  };
 
-  typedef NCollection_DataMap<Standard_ThreadId, TypeContext, Hasher> ContextMap;
+    //! Defines functor interface
+    void operator()( const Standard_Integer theIndex ) const
+    {
+      const opencascade::handle<TypeContext>& aContext = GetThreadContext();
+      typename TypeSolverVector::value_type& aSolver = mySolverVector[theIndex];
 
-public:
+      aSolver.SetContext(aContext);
+      aSolver.Perform();
+    }
 
-  //! Constructor
-  explicit BOPTools_ContextFunctor( TypeSolverVector& theVector )
-  : mySolverVector(theVector) {}
+  private:
+    ContextFunctor(const ContextFunctor&);
+    ContextFunctor& operator= (const ContextFunctor&);
 
-  //! Binds main thread context
-  void SetContext( TypeContext& theContext )
-  {
-    myContexts.Bind(OSD_Thread::Current(), theContext);
-  }
+  private:
+    TypeSolverVector& mySolverVector;
+    mutable NCollection_DataMap<Standard_ThreadId, opencascade::handle<TypeContext>, Hasher> myContextMap;
+    mutable Standard_Mutex myMutex;
+  };
 
-  //! Returns current thread context
-  TypeContext& GetThreadContext() const
+  //! Functor storing array of algorithm contexts per thread in pool
+  template<class TypeSolverVector, class TypeContext>
+  class ContextFunctor2
   {
-    const Standard_ThreadId aThreadID = OSD_Thread::Current();
-    if ( myContexts.IsBound(aThreadID) )
+  public:
+
+    //! Constructor
+    explicit ContextFunctor2 (TypeSolverVector& theVector, const OSD_ThreadPool::Launcher& thePoolLauncher)
+    : mySolverVector(theVector),
+      myContextArray (thePoolLauncher.LowerThreadIndex(), thePoolLauncher.UpperThreadIndex()) {}
+
+    //! Binds main thread context
+    void SetContext (const opencascade::handle<TypeContext>& theContext)
     {
-      TypeContext& aContext = myContexts(aThreadID);
-      if ( aContext.IsNull() == Standard_False )
-        return aContext;
+      myContextArray.ChangeLast() = theContext; // OSD_ThreadPool::Launcher::UpperThreadIndex() is reserved for a main thread
     }
 
-    // Create new context
-    TypeContext aContext = new TN
-      ( NCollection_BaseAllocator::CommonBaseAllocator() );
+    //! Defines functor interface with serialized thread index.
+    void operator() (int theThreadIndex,
+                     int theIndex) const
+    {
+      opencascade::handle<TypeContext>& aContext = myContextArray.ChangeValue (theThreadIndex);
+      if (aContext.IsNull())
+      {
+        aContext = new TypeContext (NCollection_BaseAllocator::CommonBaseAllocator());
+      }
+      typename TypeSolverVector::value_type& aSolver = mySolverVector[theIndex];
+      aSolver.SetContext (aContext);
+      aSolver.Perform();
+    }
 
-    Standard_Mutex::Sentry aLocker(myMutex);
-    myContexts.Bind(aThreadID, aContext);
+  private:
+    ContextFunctor2(const ContextFunctor2&);
+    ContextFunctor2& operator= (const ContextFunctor2&);
 
-    return myContexts(aThreadID);
-  }
+  private:
+    TypeSolverVector& mySolverVector;
+    mutable NCollection_Array1< opencascade::handle<TypeContext> > myContextArray;
+  };
 
-  //! Defines functor interface
-  void operator()( const Standard_Integer theIndex ) const
-  {
-    TypeContext& aContext = GetThreadContext();
-    TypeSolver&  aSolver  = mySolverVector(theIndex);
+public:
 
-    aSolver.SetContext(aContext);
-    aSolver.Perform();
+  //! Pure version
+  template<class TypeSolverVector>
+  static void Perform (Standard_Boolean theIsRunParallel,
+                       TypeSolverVector& theSolverVector)
+  {
+    Functor<TypeSolverVector> aFunctor (theSolverVector);
+    OSD_Parallel::For (0, theSolverVector.Length(), aFunctor, !theIsRunParallel);
   }
 
-private:
-  BOPTools_ContextFunctor(const BOPTools_ContextFunctor&);
-  BOPTools_ContextFunctor& operator= (const BOPTools_ContextFunctor&);
-
-private:
-  TypeSolverVector&      mySolverVector;
-  mutable ContextMap     myContexts;
-  mutable Standard_Mutex myMutex;
-};
-
-//=======================================================================
-//class    : BOPTools_ContextCnt
-//purpose  : 
-//=======================================================================
-template <class TypeFunctor, class TypeSolverVector, class TypeContext>
-class BOPTools_ContextCnt
-{
-public:
-  static void Perform( const Standard_Boolean isRunParallel,
-                       TypeSolverVector&      theSolverVector,
-                       TypeContext&           theContext )
+  //! Context dependent version
+  template<class TypeSolverVector, class TypeContext>
+  static void Perform (Standard_Boolean  theIsRunParallel,
+                       TypeSolverVector& theSolverVector,
+                       opencascade::handle<TypeContext>& theContext)
   {
-    TypeFunctor aFunctor(theSolverVector);
-    aFunctor.SetContext(theContext);
-
-    OSD_Parallel::For(0, theSolverVector.Length(), aFunctor, !isRunParallel);
+    if (OSD_Parallel::ToUseOcctThreads())
+    {
+      const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
+      OSD_ThreadPool::Launcher aPoolLauncher (*aThreadPool, theIsRunParallel ? theSolverVector.Length() : 0);
+      ContextFunctor2<TypeSolverVector, TypeContext> aFunctor (theSolverVector, aPoolLauncher);
+      aFunctor.SetContext (theContext);
+      aPoolLauncher.Perform (0, theSolverVector.Length(), aFunctor);
+    }
+    else
+    {
+      ContextFunctor<TypeSolverVector, TypeContext> aFunctor (theSolverVector);
+      aFunctor.SetContext (theContext);
+      OSD_Parallel::For (0, theSolverVector.Length(), aFunctor, !theIsRunParallel);
+    }
   }
 };