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