summaryrefslogtreecommitdiff
path: root/src/itoqueue.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/itoqueue.h')
-rw-r--r--src/itoqueue.h231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/itoqueue.h b/src/itoqueue.h
new file mode 100644
index 0000000..75a2f27
--- /dev/null
+++ b/src/itoqueue.h
@@ -0,0 +1,231 @@
1#ifndef BU_ITO_QUEUE_H
2#define BU_ITO_QUEUE_H
3
4#include <pthread.h>
5
6#include "itomutex.h"
7#include "itocondition.h"
8
9namespace Bu
10{
11 /**
12 * A thread-safe queue class. This class is a very simple queue with some cool
13 * extra functionality for use with the Ito system. The main extra that it
14 * provides is the option to either dequeue without blocking, with infinite
15 * blocking, or with timed blocking, which will return a value if something is
16 * enqueued within the specified time limit, or NULL if the time limit is
17 * exceded.
18 *@author Mike Buland
19 */
20 template <class T>
21 class ItoQueue
22 {
23 private:
24 /**
25 * Helper struct. Keeps track of linked-list items for the queue data.
26 */
27 typedef struct Item
28 {
29 T pData;
30 Item *pNext;
31 } Item;
32
33 public:
34 /**
35 * Construct an empty queue.
36 */
37 ItoQueue() :
38 pStart( NULL ),
39 pEnd( NULL ),
40 nSize( 0 )
41 {
42 }
43
44 /**
45 * Destroy the queue. This function will simply free all contained
46 * structures. If you stored pointers in the queue, this will lose the
47 * pointers without cleaning up the memory they pointed to. Make sure
48 * you're queue is empty before allowing it to be destroyed!
49 */
50 ~ItoQueue()
51 {
52 Item *pCur = pStart;
53 while( pCur )
54 {
55 Item *pTmp = pCur->pNext;
56 delete pCur;
57 pCur = pTmp;
58 }
59 }
60
61 /**
62 * Enqueue a pieces of data. The new data will go at the end of the queue,
63 * and unless another piece of data is enqueued, will be the last piece of
64 * data to be dequeued.
65 *@param pData The data to enqueue. If this is not a primitive data type
66 * it's probably best to use a pointer type.
67 */
68 void enqueue( T pData )
69 {
70 mOperate.lock();
71
72 if( pStart == NULL )
73 {
74 pStart = pEnd = new Item;
75 pStart->pData = pData;
76 pStart->pNext = NULL;
77 nSize++;
78 }
79 else
80 {
81 pEnd->pNext = new Item;
82 pEnd = pEnd->pNext;
83 pEnd->pData = pData;
84 pEnd->pNext = NULL;
85 nSize++;
86 }
87
88 cBlock.signal();
89
90 mOperate.unlock();
91 }
92
93 /**
94 * Dequeue the first item from the queue. This function can operate in two
95 * different modes, blocking and non-blocking. In non-blocking mode it will
96 * return immediately weather there was data in the queue or not. If there
97 * was data it will remove it from the queue and return it to the caller.
98 * In blocking mode it will block forever wating for data to be enqueued.
99 * When data finally is enqueued this function will return immediately with
100 * the new data. The only way this function should ever return a null in
101 * blocking mode is if the calling thread was cancelled. It's probably a
102 * good idea to check for NULL return values even if you use blocking, just
103 * to be on the safe side.
104 *@param bBlock Set to true to enable blocking, leave as false to work in
105 * non-blocking mode.
106 *@returns The next piece of data in the queue, or NULL if no data was in
107 * the queue.
108 */
109 T dequeue( bool bBlock=false )
110 {
111 mOperate.lock();
112 if( pStart == NULL )
113 {
114 mOperate.unlock();
115
116 if( bBlock )
117 {
118 cBlock.lock();
119
120 while( pStart == NULL )
121 cBlock.wait();
122
123 T tmp = dequeue( false );
124
125 cBlock.unlock();
126 return tmp;
127
128 }
129
130 return NULL;
131 }
132 else
133 {
134 T pTmp = pStart->pData;
135 Item *pDel = pStart;
136 pStart = pStart->pNext;
137 delete pDel;
138 nSize--;
139
140 mOperate.unlock();
141 return pTmp;
142 }
143 }
144
145 /**
146 * Operates just like the other dequeue function in blocking mode with one
147 * twist. This function will block for at most nSec seconds and nUSec
148 * micro-seconds. If the timer is up and no data is available, this will
149 * just return NULL. If data is enqueued before the timeout expires, it
150 * will dequeue and exit immediately.
151 *@param nSec The number of seconds to wait, max.
152 *@param nUSec The number of micro-seconds to wait, max.
153 *@returns The next piece of data in the queue, or NULL if the timeout was
154 * exceeded.
155 */
156 T dequeue( int nSec, int nUSec )
157 {
158 mOperate.lock();
159 if( pStart == NULL )
160 {
161 mOperate.unlock();
162
163 cBlock.lock();
164
165 cBlock.wait( nSec, nUSec );
166
167 if( pStart == NULL )
168 {
169 cBlock.unlock();
170 return NULL;
171 }
172
173 mOperate.lock();
174 T pTmp = pStart->pData;
175 Item *pDel = pStart;
176 pStart = pStart->pNext;
177 delete pDel;
178 nSize--;
179 mOperate.unlock();
180
181 cBlock.unlock();
182 return pTmp;
183 }
184 else
185 {
186 T pTmp = pStart->pData;
187 Item *pDel = pStart;
188 pStart = pStart->pNext;
189 delete pDel;
190 nSize--;
191
192 mOperate.unlock();
193 return pTmp;
194 }
195 }
196
197 /**
198 * Checks to see if the queue has data in it or not. Note that there is no
199 * function to determine the length of the queue. This data isn't kept
200 * track of. If you really need to know, fix this.
201 *@returns True if the queue is empty, false if it has data in it.
202 */
203 bool isEmpty()
204 {
205 mOperate.lock();
206 bool bEmpty = (pStart == NULL );
207 mOperate.unlock();
208
209 return bEmpty;
210 }
211
212 long getSize()
213 {
214 mOperate.lock();
215 long nRet = nSize;
216 mOperate.unlock();
217
218 return nRet;
219 }
220
221 private:
222 Item *pStart; /**< The start of the queue, the next element to dequeue. */
223 Item *pEnd; /**< The end of the queue, the last element to dequeue. */
224 long nSize; /**< The number of items in the queue. */
225
226 ItoMutex mOperate; /**< The master mutex, used on all operations. */
227 ItoCondition cBlock; /**< The condition for blocking dequeues. */
228 };
229}
230
231#endif