0031757: Visualization - Prebuild BVH for Select3D_SensitiveEntity in separate threads
[occt.git] / src / SelectMgr / SelectMgr_BVHThreadPool.hxx
1 // Copyright (c) 2020 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #ifndef _SelectMgr_BVHThreadPool_HeaderFile
15 #define _SelectMgr_BVHThreadPool_HeaderFile
16
17 #include <Standard_Transient.hxx>
18 #include <OSD_Thread.hxx>
19 #include <Standard_Mutex.hxx>
20 #include <Select3D_SensitiveEntity.hxx>
21 #include <Standard_Condition.hxx>
22 #include <Message_Messenger.hxx>
23
24 //! Class defining a thread pool for building BVH for the list of Select3D_SensitiveEntity within background thread(s).
25 class SelectMgr_BVHThreadPool : public Standard_Transient
26 {
27   DEFINE_STANDARD_RTTIEXT(SelectMgr_BVHThreadPool, Standard_Transient)
28 public:
29   //! Main constructor
30   Standard_EXPORT SelectMgr_BVHThreadPool (Standard_Integer theNbThreads);
31
32   //! Destructor
33   Standard_EXPORT virtual ~SelectMgr_BVHThreadPool();
34
35 public:
36
37   //! Thread with back reference to thread pool and thread mutex in it.
38   class BVHThread : public OSD_Thread
39   {
40     friend class SelectMgr_BVHThreadPool;
41   public:
42
43     BVHThread()
44       : OSD_Thread(),
45       myToCatchFpe (Standard_False)
46     {
47
48     }
49
50     //! Returns mutex used for BVH building
51     Standard_Mutex& BVHMutex()
52     {
53       return myMutex;
54     }
55
56     //! Assignment operator.
57     BVHThread& operator= (const BVHThread& theCopy)
58     {
59       Assign (theCopy);
60       return *this;
61     }
62
63     //! Assignment operator.
64     void Assign (const BVHThread& theCopy)
65     {
66       OSD_Thread::Assign (theCopy);
67       myPool = theCopy.myPool;
68       myToCatchFpe = theCopy.myToCatchFpe;
69     }
70
71   private:
72     //! Method is executed in the context of thread.
73     void performThread();
74
75     //! Method is executed in the context of thread.
76     static Standard_Address runThread (Standard_Address theTask);
77
78   private:
79
80     SelectMgr_BVHThreadPool* myPool;
81     Standard_Mutex myMutex;
82     bool myToCatchFpe;
83   };
84
85 public:
86   //! Queue a sensitive entity to build its BVH
87   Standard_EXPORT void AddEntity (const Handle(Select3D_SensitiveEntity)& theEntity);
88
89   //! Stops threads
90   Standard_EXPORT void StopThreads();
91
92   //! Waits for all threads finish their jobs
93   Standard_EXPORT void WaitThreads();
94
95   //! Returns array of threads
96   NCollection_Array1<BVHThread>& Threads()
97   {
98     return myBVHThreads;
99   }
100
101 public:
102
103   //! Class providing a simple interface to mutexes for list of BVHThread
104   class Sentry 
105   {
106   public:
107
108     //! Constructor - initializes the sentry object and locks list of mutexes immediately
109     Sentry (const Handle(SelectMgr_BVHThreadPool)& thePool)
110     : myPool (thePool)
111     {
112       Lock();
113     }
114     
115     //! Destructor - unlocks list of mutexes if already locked.
116     ~Sentry()
117     {
118         Unlock();
119     }
120
121     //! Lock list of mutexes
122     void Lock()
123     {
124       if (!myPool.IsNull())
125       {
126         for (Standard_Integer i = myPool->Threads().Lower(); i <= myPool->Threads().Upper(); ++i)
127         {
128           myPool->Threads().ChangeValue(i).BVHMutex().Lock();
129         }
130       }
131     }
132
133     //! Unlock list of mutexes
134     void Unlock()
135     {
136       if (!myPool.IsNull())
137       {
138         for (Standard_Integer i = myPool->Threads().Lower(); i <= myPool->Threads().Upper(); ++i)
139         {
140           myPool->Threads().ChangeValue(i).BVHMutex().Unlock();
141         }
142       }
143     }
144
145     //! This method should not be called (prohibited).
146     Sentry (const Sentry &);
147     //! This method should not be called (prohibited).
148     Sentry& operator = (const Sentry &);
149
150   private:
151     Handle(SelectMgr_BVHThreadPool) myPool;
152   };
153
154 protected:
155
156   NCollection_List<Handle(Select3D_SensitiveEntity)> myBVHToBuildList; //!< list of queued sensitive entities
157   NCollection_Array1<BVHThread> myBVHThreads;                          //!< threads to build BVH
158   Standard_Boolean myToStopBVHThread;                                  //!< flag to stop BVH threads
159   Standard_Mutex myBVHListMutex;                                       //!< mutex for interaction with myBVHToBuildList
160   Standard_Condition myWakeEvent;                                      //!< raises when any sensitive is added to the BVH list
161   Standard_Condition myIdleEvent;                                      //!< raises when BVH list become empty
162   Standard_Boolean myIsStarted;                                        //!< indicates that threads are running
163 };
164
165 #endif