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