1 #ifndef OPENMW_COMPONENTS_SCENEUTIL_WORKQUEUE_H 2 #define OPENMW_COMPONENTS_SCENEUTIL_WORKQUEUE_H 3 4 #include <osg/Referenced> 5 #include <osg/ref_ptr> 6 7 #include <atomic> 8 #include <queue> 9 #include <thread> 10 #include <mutex> 11 #include <condition_variable> 12 13 namespace SceneUtil 14 { 15 16 class WorkItem : public osg::Referenced 17 { 18 public: 19 /// Override in a derived WorkItem to perform actual work. doWork()20 virtual void doWork() {} 21 22 bool isDone() const; 23 24 /// Wait until the work is completed. Usually called from the main thread. 25 void waitTillDone(); 26 27 /// Internal use by the WorkQueue. 28 void signalDone(); 29 30 /// Set abort flag in order to return from doWork() as soon as possible. May not be respected by all WorkItems. abort()31 virtual void abort() {} 32 33 private: 34 std::atomic_bool mDone {false}; 35 std::mutex mMutex; 36 std::condition_variable mCondition; 37 }; 38 39 class WorkThread; 40 41 /// @brief A work queue that users can push work items onto, to be completed by one or more background threads. 42 /// @note Work items will be processed in the order that they were given in, however 43 /// if multiple work threads are involved then it is possible for a later item to complete before earlier items. 44 class WorkQueue : public osg::Referenced 45 { 46 public: 47 WorkQueue(int numWorkerThreads=1); 48 ~WorkQueue(); 49 50 /// Add a new work item to the back of the queue. 51 /// @par The work item's waitTillDone() method may be used by the caller to wait until the work is complete. 52 /// @param front If true, add item to the front of the queue. If false (default), add to the back. 53 void addWorkItem(osg::ref_ptr<WorkItem> item, bool front=false); 54 55 /// Get the next work item from the front of the queue. If the queue is empty, waits until a new item is added. 56 /// If the workqueue is in the process of being destroyed, may return nullptr. 57 /// @par Used internally by the WorkThread. 58 osg::ref_ptr<WorkItem> removeWorkItem(); 59 60 unsigned int getNumItems() const; 61 62 unsigned int getNumActiveThreads() const; 63 64 private: 65 bool mIsReleased; 66 std::deque<osg::ref_ptr<WorkItem> > mQueue; 67 68 mutable std::mutex mMutex; 69 std::condition_variable mCondition; 70 71 std::vector<std::unique_ptr<WorkThread>> mThreads; 72 }; 73 74 /// Internally used by WorkQueue. 75 class WorkThread 76 { 77 public: 78 WorkThread(WorkQueue& workQueue); 79 80 ~WorkThread(); 81 82 bool isActive() const; 83 84 private: 85 WorkQueue* mWorkQueue; 86 std::atomic<bool> mActive; 87 std::thread mThread; 88 89 void run(); 90 }; 91 92 93 } 94 95 #endif 96