1 // Created by: Peter KURNEV
2 // Copyright (c) 1999-2013 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14 
15 #ifndef _BOPTools_Parallel_HeaderFile
16 #define _BOPTools_Parallel_HeaderFile
17 
18 #include <Standard_Macro.hxx>
19 #include <Standard_NotImplemented.hxx>
20 #include <OSD_Parallel.hxx>
21 #include <OSD_ThreadPool.hxx>
22 #include <NCollection_DataMap.hxx>
23 #include <Standard_Mutex.hxx>
24 #include <OSD_Thread.hxx>
25 
26 //! Implementation of Functors/Starters
27 class BOPTools_Parallel
28 {
29   template<class TypeSolverVector>
30   class Functor
31   {
32   public:
33     //! Constructor.
Functor(TypeSolverVector & theSolverVec)34     explicit Functor(TypeSolverVector& theSolverVec) : mySolvers (theSolverVec) {}
35 
36     //! Defines functor interface.
operator ()(const Standard_Integer theIndex) const37     void operator() (const Standard_Integer theIndex) const
38     {
39       typename TypeSolverVector::value_type& aSolver = mySolvers[theIndex];
40       aSolver.Perform();
41     }
42 
43   private:
44     Functor(const Functor&);
45     Functor& operator= (const Functor&);
46 
47   private:
48     TypeSolverVector& mySolvers;
49   };
50 
51   //! Functor storing map of thread id -> algorithm context
52   template<class TypeSolverVector, class TypeContext>
53   class ContextFunctor
54   {
55     //! Auxiliary thread ID  hasher.
56     struct Hasher
57     {
58       //! Computes a hash code for the given thread identifier, in the range [1, theUpperBound]
59       //! @param theThreadId the thread identifier which hash code is to be computed
60       //! @param theUpperBound the upper bound of the range a computing hash code must be within
61       //! @return a computed hash code, in the range [1, theUpperBound]
HashCodeBOPTools_Parallel::ContextFunctor::Hasher62       static Standard_Integer HashCode (const Standard_ThreadId theThreadId, const Standard_Integer theUpperBound)
63       {
64         return ::HashCode (theThreadId, theUpperBound);
65       }
66 
IsEqualBOPTools_Parallel::ContextFunctor::Hasher67       static Standard_Boolean IsEqual(const Standard_ThreadId theKey1,
68                                       const Standard_ThreadId theKey2)
69       {
70         return theKey1 == theKey2;
71       }
72     };
73 
74   public:
75 
76     //! Constructor
ContextFunctor(TypeSolverVector & theVector)77     explicit ContextFunctor (TypeSolverVector& theVector) : mySolverVector(theVector) {}
78 
79     //! Binds main thread context
SetContext(const opencascade::handle<TypeContext> & theContext)80     void SetContext (const opencascade::handle<TypeContext>& theContext)
81     {
82       myContextMap.Bind (OSD_Thread::Current(), theContext);
83     }
84 
85     //! Returns current thread context
GetThreadContext() const86     const opencascade::handle<TypeContext>& GetThreadContext() const
87     {
88       const Standard_ThreadId aThreadID = OSD_Thread::Current();
89       if (const opencascade::handle<TypeContext>* aContextPtr = myContextMap.Seek (aThreadID))
90       {
91         if (!aContextPtr->IsNull())
92         {
93           return *aContextPtr;
94         }
95       }
96 
97       // Create new context
98       opencascade::handle<TypeContext> aContext = new TypeContext (NCollection_BaseAllocator::CommonBaseAllocator());
99 
100       Standard_Mutex::Sentry aLocker (myMutex);
101       myContextMap.Bind (aThreadID, aContext);
102       return myContextMap (aThreadID);
103     }
104 
105     //! Defines functor interface
operator ()(const Standard_Integer theIndex) const106     void operator()( const Standard_Integer theIndex ) const
107     {
108       const opencascade::handle<TypeContext>& aContext = GetThreadContext();
109       typename TypeSolverVector::value_type& aSolver = mySolverVector[theIndex];
110 
111       aSolver.SetContext(aContext);
112       aSolver.Perform();
113     }
114 
115   private:
116     ContextFunctor(const ContextFunctor&);
117     ContextFunctor& operator= (const ContextFunctor&);
118 
119   private:
120     TypeSolverVector& mySolverVector;
121     mutable NCollection_DataMap<Standard_ThreadId, opencascade::handle<TypeContext>, Hasher> myContextMap;
122     mutable Standard_Mutex myMutex;
123   };
124 
125   //! Functor storing array of algorithm contexts per thread in pool
126   template<class TypeSolverVector, class TypeContext>
127   class ContextFunctor2
128   {
129   public:
130 
131     //! Constructor
ContextFunctor2(TypeSolverVector & theVector,const OSD_ThreadPool::Launcher & thePoolLauncher)132     explicit ContextFunctor2 (TypeSolverVector& theVector, const OSD_ThreadPool::Launcher& thePoolLauncher)
133     : mySolverVector(theVector),
134       myContextArray (thePoolLauncher.LowerThreadIndex(), thePoolLauncher.UpperThreadIndex()) {}
135 
136     //! Binds main thread context
SetContext(const opencascade::handle<TypeContext> & theContext)137     void SetContext (const opencascade::handle<TypeContext>& theContext)
138     {
139       myContextArray.ChangeLast() = theContext; // OSD_ThreadPool::Launcher::UpperThreadIndex() is reserved for a main thread
140     }
141 
142     //! Defines functor interface with serialized thread index.
operator ()(int theThreadIndex,int theIndex) const143     void operator() (int theThreadIndex,
144                      int theIndex) const
145     {
146       opencascade::handle<TypeContext>& aContext = myContextArray.ChangeValue (theThreadIndex);
147       if (aContext.IsNull())
148       {
149         aContext = new TypeContext (NCollection_BaseAllocator::CommonBaseAllocator());
150       }
151       typename TypeSolverVector::value_type& aSolver = mySolverVector[theIndex];
152       aSolver.SetContext (aContext);
153       aSolver.Perform();
154     }
155 
156   private:
157     ContextFunctor2(const ContextFunctor2&);
158     ContextFunctor2& operator= (const ContextFunctor2&);
159 
160   private:
161     TypeSolverVector& mySolverVector;
162     mutable NCollection_Array1< opencascade::handle<TypeContext> > myContextArray;
163   };
164 
165 public:
166 
167   //! Pure version
168   template<class TypeSolverVector>
Perform(Standard_Boolean theIsRunParallel,TypeSolverVector & theSolverVector)169   static void Perform (Standard_Boolean theIsRunParallel,
170                        TypeSolverVector& theSolverVector)
171   {
172     Functor<TypeSolverVector> aFunctor (theSolverVector);
173     OSD_Parallel::For (0, theSolverVector.Length(), aFunctor, !theIsRunParallel);
174   }
175 
176   //! Context dependent version
177   template<class TypeSolverVector, class TypeContext>
Perform(Standard_Boolean theIsRunParallel,TypeSolverVector & theSolverVector,opencascade::handle<TypeContext> & theContext)178   static void Perform (Standard_Boolean  theIsRunParallel,
179                        TypeSolverVector& theSolverVector,
180                        opencascade::handle<TypeContext>& theContext)
181   {
182     if (OSD_Parallel::ToUseOcctThreads())
183     {
184       const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
185       OSD_ThreadPool::Launcher aPoolLauncher (*aThreadPool, theIsRunParallel ? theSolverVector.Length() : 0);
186       ContextFunctor2<TypeSolverVector, TypeContext> aFunctor (theSolverVector, aPoolLauncher);
187       aFunctor.SetContext (theContext);
188       aPoolLauncher.Perform (0, theSolverVector.Length(), aFunctor);
189     }
190     else
191     {
192       ContextFunctor<TypeSolverVector, TypeContext> aFunctor (theSolverVector);
193       aFunctor.SetContext (theContext);
194       OSD_Parallel::For (0, theSolverVector.Length(), aFunctor, !theIsRunParallel);
195     }
196   }
197 };
198 
199 #endif
200