vsg 1.1.13
VulkanSceneGraph library
Loading...
Searching...
No Matches
OperationQueue.h
1#pragma once
2
3/* <editor-fold desc="MIT License">
4
5Copyright(c) 2018 Robert Osfield
6
7Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
9The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12
13</editor-fold> */
14
15#include <vsg/io/Logger.h>
16#include <vsg/threading/ActivityStatus.h>
17#include <vsg/threading/Latch.h>
18
19#include <list>
20
21namespace vsg
22{
23 enum InsertionPosition
24 {
25 INSERT_FRONT,
26 INSERT_BACK
27 };
28
30 template<class T>
31 class ThreadSafeQueue : public Inherit<Object, ThreadSafeQueue<T>>
32 {
33 public:
34 using value_type = T;
35 using container_type = std::list<value_type>;
36
37 explicit ThreadSafeQueue(ref_ptr<ActivityStatus> status) :
38 _status(status)
39 {
40 }
41
42 ActivityStatus* getStatus() { return _status; }
43 const ActivityStatus* getStatus() const { return _status; }
44
46 void add(value_type operation, InsertionPosition insertionPosition = INSERT_BACK)
47 {
48 std::scoped_lock lock(_mutex);
49 if (insertionPosition == INSERT_BACK)
50 _queue.emplace_back(operation);
51 else
52 _queue.emplace_front(operation);
53 _cv.notify_one();
54 }
55
57 template<typename Iterator>
58 void add(Iterator begin, Iterator end, InsertionPosition insertionPosition = INSERT_BACK)
59 {
60 size_t numAdditions = 0;
61 std::scoped_lock lock(_mutex);
62 for (auto itr = begin; itr != end; ++itr)
63 {
64 if (insertionPosition == INSERT_BACK)
65 _queue.emplace_back(*itr);
66 else
67 _queue.emplace_front(*itr);
68 ++numAdditions;
69 }
70
71 if (numAdditions == 1)
72 _cv.notify_one();
73 else if (numAdditions > 1)
74 _cv.notify_all();
75 }
76
78 bool empty() const
79 {
80 std::unique_lock lock(_mutex);
81 return _queue.empty();
82 }
83
85 container_type take_all()
86 {
87 std::unique_lock lock(_mutex);
88
89 container_type objects;
90 objects.swap(_queue);
91
92 return objects;
93 }
94
96 value_type take()
97 {
98 std::unique_lock lock(_mutex);
99
100 if (_queue.empty()) return {};
101
102 auto operation = _queue.front();
103
104 _queue.erase(_queue.begin());
105
106 return operation;
107 }
108
111 {
112 std::chrono::duration waitDuration = std::chrono::milliseconds(100);
113
114 std::unique_lock lock(_mutex);
115
116 // wait until the conditional variable signals that an operation has been added
117 while (_queue.empty() && _status->active())
118 {
119 // debug("Waiting on condition variable");
120 _cv.wait_for(lock, waitDuration);
121 }
122
123 // if the threads we are associated with should no longer be running go for a quick exit and return nothing.
124 if (_status->cancel())
125 {
126 return {};
127 }
128
129 // remove and return the head of the queue
130 auto operation = _queue.front();
131 _queue.erase(_queue.begin());
132 return operation;
133 }
134
135 protected:
136 mutable std::mutex _mutex;
137 std::condition_variable _cv;
138 container_type _queue;
140 };
141
142 // clang-format screws up handling of VSG_type_name macro so have to switch it off.
143 // clang-format off
144
146 struct Operation : public Object
147 {
148 virtual void run() = 0;
149 };
150 VSG_type_name(vsg::Operation)
151
152
153 using OperationQueue = ThreadSafeQueue<ref_ptr<Operation>>;
154 VSG_type_name(vsg::OperationQueue)
155
156} // namespace vsg
ActivityStatus provides atomic management of whether threads watching this ActivityStatus object shou...
Definition ActivityStatus.h:22
Template thread safe queue.
Definition OperationQueue.h:32
value_type take()
take the head from the queue of objects, return null pointer if none are available
Definition OperationQueue.h:96
container_type take_all()
take all available objects from the queue
Definition OperationQueue.h:85
value_type take_when_available()
take the head of the queue, waiting till one is made available if initially empty
Definition OperationQueue.h:110
void add(Iterator begin, Iterator end, InsertionPosition insertionPosition=INSERT_BACK)
add multiple objects to the back of the queue
Definition OperationQueue.h:58
void add(value_type operation, InsertionPosition insertionPosition=INSERT_BACK)
add a single object to the back of the queue
Definition OperationQueue.h:46
bool empty() const
return true if the queue is empty.
Definition OperationQueue.h:78
Definition ref_ptr.h:22
Operation base class.
Definition OperationQueue.h:147