0029935: Foundation Classes - introduce OSD_ThreadPool class defining a thread pool
[occt.git] / src / OSD / OSD_Parallel_Threads.cxx
1 // Created on: 2014-08-19
2 // Created by: Alexander Zaikin
3 // Copyright (c) 1996-1999 Matra Datavision
4 // Copyright (c) 2013-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 // Version of parallel executor used when TBB is not available
18 #ifndef HAVE_TBB
19
20 #include <OSD_Parallel.hxx>
21
22 #include <OSD_ThreadPool.hxx>
23
24 #include <NCollection_Array1.hxx>
25 #include <Standard_Mutex.hxx>
26 #include <OSD_Thread.hxx>
27
28 namespace 
29 {
30   //! Class implementing tools for parallel processing 
31   //! using threads (when TBB is not available);
32   //! it is derived from OSD_Parallel to get access to 
33   //! Iterator and FunctorInterface nested types.
34   class OSD_Parallel_Threads : public OSD_ThreadPool, public OSD_Parallel
35   {
36   public:
37     //! Auxiliary class which ensures exclusive
38     //! access to iterators of processed data pool.
39     class Range
40     {
41     public: //! @name public methods
42
43       //! Constructor
44       Range(const OSD_Parallel::UniversalIterator& theBegin,
45             const OSD_Parallel::UniversalIterator& theEnd)
46       : myBegin(theBegin),
47         myEnd(theEnd),
48         myIt(theBegin)
49       {
50       }
51
52       //! Returns const link on the first element.
53       inline const OSD_Parallel::UniversalIterator& Begin() const
54       {
55         return myBegin;
56       }
57
58       //! Returns const link on the last element.
59       inline const OSD_Parallel::UniversalIterator& End() const
60       {
61         return myEnd;
62       }
63
64       //! Returns first non processed element or end.
65       //! Thread-safe method.
66       inline OSD_Parallel::UniversalIterator It() const
67       {
68         Standard_Mutex::Sentry aMutex(myMutex);
69         return (myIt != myEnd) ? myIt++ : myEnd;
70       }
71
72     private: //! @name private methods
73
74       //! Empty copy constructor
75       Range(const Range& theCopy);
76
77       //! Empty copy operator.
78       Range& operator=(const Range& theCopy);
79
80     private: //! @name private fields
81
82       const   OSD_Parallel::UniversalIterator&  myBegin; //!< Fisrt element of range.
83       const   OSD_Parallel::UniversalIterator&  myEnd;   //!< Last element of range.
84       mutable OSD_Parallel::UniversalIterator   myIt;    //!< First non processed element of range.
85       mutable Standard_Mutex                 myMutex; //!< Access controller for the first non processed element.
86     };
87
88     //! Auxiliary wrapper class for thread function.
89     class Task : public JobInterface
90     {
91     public: //! @name public methods
92
93       //! Constructor.
94       Task(const OSD_Parallel::FunctorInterface& thePerformer, Range& theRange)
95         : myPerformer(thePerformer),
96         myRange(theRange)
97       {
98       }
99
100       //! Method is executed in the context of thread,
101       //! so this method defines the main calculations.
102       virtual void Perform (int ) Standard_OVERRIDE
103       {
104         for (OSD_Parallel::UniversalIterator anIter = myRange.It(); anIter != myRange.End(); anIter = myRange.It())
105         {
106           myPerformer (anIter);
107         }
108       }
109
110     private: //! @name private methods
111
112       //! Empty copy constructor.
113       Task(const Task& theCopy);
114
115       //! Empty copy operator.
116       Task& operator=(const Task& theCopy);
117
118     private: //! @name private fields
119       const FunctorInterface& myPerformer; //!< Link on functor
120       const Range& myRange; //!< Link on processed data block
121     };
122
123     //! Launcher specialization.
124     class UniversalLauncher : public Launcher
125     {
126     public:
127       //! Constructor.
128       UniversalLauncher (OSD_ThreadPool& thePool, int theMaxThreads = -1)
129       : Launcher (thePool, theMaxThreads) {}
130
131       //! Primitive for parallelization of "for" loops.
132       void Perform (OSD_Parallel::UniversalIterator& theBegin,
133                     OSD_Parallel::UniversalIterator& theEnd,
134                     const OSD_Parallel::FunctorInterface& theFunctor)
135       {
136         Range aData (theBegin, theEnd);
137         Task aJob (theFunctor, aData);
138         perform (aJob);
139       }
140     };
141   };
142 }
143
144 //=======================================================================
145 //function : forEach
146 //purpose  : 
147 //=======================================================================
148 void OSD_Parallel::forEach (UniversalIterator& theBegin,
149                             UniversalIterator& theEnd,
150                             const FunctorInterface& theFunctor,
151                             Standard_Integer theNbItems)
152 {
153   const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
154   const Standard_Integer aNbThreads = theNbItems != -1 ? Min (theNbItems, aThreadPool->NbDefaultThreadsToLaunch()) : -1;
155   OSD_Parallel_Threads::UniversalLauncher aLauncher (*aThreadPool, aNbThreads);
156   aLauncher.Perform (theBegin, theEnd, theFunctor);
157 }
158
159 #endif /* ! HAVE_TBB */