HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_ThreadQueue.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_ThreadQueue.h ( UT Library, C++)
7  *
8  * COMMENTS:
9  * Modelled after Python's Queue, this is a simple queue
10  * which you can use to communicate to another thread with.
11  */
12 
13 #ifndef __UT_ThreadQueue__
14 #define __UT_ThreadQueue__
15 
16 #include "UT_API.h"
17 #include "UT_Condition.h"
18 #include "UT_NonCopyable.h"
19 #include "UT_RingBuffer.h"
20 #include "UT_Thread.h"
21 #include <utility>
22 
23 ///
24 /// UT_ThreadQueue
25 ///
26 /// Designed to be templated on a POD.
27 ///
28 template <typename T>
30 {
31 public:
32  /// A max cost of -1 will never block on adding items to the queue.
33  UT_ThreadQueue(exint maxcost = -1)
34  {
35  myMaxCost = maxcost;
36  myCurrentCost = 0;
37  }
39 
40  /// Prohibit copying as I am not sure if lock semantics will work.
42 
43  /// Synchronized test for number of entries
44  int entries() const
45  {
46  UT_AutoLock l(myLock);
47 
48  return myList.entries();
49  }
50 
51  /// Removes an item, returns false if failed to remove because
52  /// the queue was empty.
53  bool remove(T &item)
54  {
55  UT_AutoLock l(myLock);
56 
57  if (isEmpty())
58  return false;
59  item = std::move(myList.popFirst());
60  exint cost = myCost.popFirst();
61  myCurrentCost -= cost;
62 
63  // Let people know it may now be empty.
64  myCond.triggerAll();
65  return true;
66  }
67 
68  /// Blocks until the item is ready.
70  {
71  UT_AutoLock l(myLock);
72  T result;
73 
74  while (!remove(result))
75  {
76  myCond.waitForTrigger(myLock);
77  }
78  return result;
79  }
80 
81  /// Timed block until item is ready, returns false if timed
82  /// out. Not guaranteed to wait the entire length of timeout_ms
83  /// before returning failure.
84  bool waitAndRemoveMS(T &item, int64 timeout_ms)
85  {
86  UT_AutoLock l(myLock);
87 
88  // Trivial success...
89  if (remove(item))
90  return true;
91 
92  // Timed block....
93  myCond.waitForTriggerMS(myLock, timeout_ms);
94 
95  // Even if it timed out, it may be we now have an item,
96  // so just re-run remove().
97  return remove(item);
98  }
99 
100  /// Blocks until the queue is empty.
101  /// May not still be empty, since someone could add after
102  /// you reach empty!
104  {
105  UT_AutoLock l(myLock);
106 
107  while (!isEmpty())
108  {
109  myCond.waitForTrigger(myLock);
110  }
111  }
112 
113  /// Blocks until a queue change occurs, returns the new queue size.
114  /// Returns zero immediately if queue is empty.
116  {
117  UT_AutoLock l(myLock);
118 
119  if (isEmpty())
120  return 0;
121 
122  myCond.waitForTrigger(myLock);
123  return myList.entries();
124  }
125 
126  /// Blocks until a queue change occurs, returns the new queue size.
127  /// Returns zero immediately if queue is empty.
128  int waitForQueueChangeMS(int64 timeout_ms)
129  {
130  UT_AutoLock l(myLock);
131 
132  if (isEmpty())
133  return 0;
134 
135  myCond.waitForTriggerMS(myLock, timeout_ms);
136  return myList.entries();
137  }
138 
139  /// Adds the item to the queue.
140  /// Will block if it the total cost would be exceeded by
141  /// adding this to the queue.
142  /// Zero cost never block, nor does a max cost of -1
143  /// @{
144  void append(const T &item, exint cost = 0)
145  { appendImpl(item, cost); }
146  void append(T &&item, exint cost = 0)
147  { appendImpl(std::move(item), cost); }
148  /// @}
149 
150 private:
151  /// Non-synchronized, do not call outside of the lock.
152  bool isEmpty() const
153  {
154  return !myList.entries();
155  }
156 
157  template <typename S>
158  void appendImpl(S &&item, exint cost)
159  {
160  UT_AutoLock l(myLock);
161 
162  // Check if we'll exceed the cost.
163  while (1)
164  {
165  // IF we are empty, add even if too expensive!
166  if (cost && myMaxCost >= 0 && (myCurrentCost > 0) && (myCurrentCost + cost > myMaxCost))
167  {
168  // Too expensive to add right now, so await a trigger.
169  myCond.waitForTrigger(myLock);
170  }
171  else
172  {
173  // Enough room for the new item.
174  break;
175  }
176  }
177 
178  // Append
179  myList.push(std::forward<S>(item));
180  myCost.push(cost);
181  myCurrentCost += cost;
182 
183  // Alert anyone waiting to wake up.
184  myCond.triggerAll();
185  }
186 
187 private:
188  UT_RingBuffer<T> myList;
189  UT_RingBuffer<exint> myCost;
190  exint myMaxCost;
191  exint myCurrentCost;
192 
193  mutable UT_Lock myLock;
194  UT_Condition myCond;
195 };
196 
197 #endif
198 
199 
bool waitForTriggerMS(UT_Lock &lock, int64 timeout_msec)
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
SYS_NO_DISCARD_RESULT T popFirst()
Definition: UT_RingBuffer.h:53
int64 exint
Definition: SYS_Types.h:125
**But if you need a result
Definition: thread.h:613
bool waitAndRemoveMS(T &item, int64 timeout_ms)
int waitForQueueChangeMS(int64 timeout_ms)
Condition synchronization primitive.
Definition: UT_Condition.h:25
int waitForQueueChange()
UT_ThreadQueue(exint maxcost=-1)
A max cost of -1 will never block on adding items to the queue.
void waitForTrigger(UT_Lock &lock)
void append(const T &item, exint cost=0)
#define UT_NON_COPYABLE(CLASS)
Define deleted copy constructor and assignment operator inside a class.
long long int64
Definition: SYS_Types.h:116
void triggerAll()
int push(const T &data)
Definition: UT_RingBuffer.h:63
void append(T &&item, exint cost=0)
T waitAndRemove()
Blocks until the item is ready.
int entries() const
Prohibit copying as I am not sure if lock semantics will work.