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