aboutsummaryrefslogtreecommitdiff
path: root/src/synchroqueue.h
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2011-10-23 07:43:50 +0000
committerMike Buland <eichlan@xagasoft.com>2011-10-23 07:43:50 +0000
commitda1e0ef0772b078bd295301bd675afdee00d40e9 (patch)
tree7d1703bbb5c2d76e6e6300e51f0ed1e09704af4f /src/synchroqueue.h
parent208b983734d7431699f4bd3534e08321e42ada86 (diff)
downloadlibbu++-da1e0ef0772b078bd295301bd675afdee00d40e9.tar.gz
libbu++-da1e0ef0772b078bd295301bd675afdee00d40e9.tar.bz2
libbu++-da1e0ef0772b078bd295301bd675afdee00d40e9.tar.xz
libbu++-da1e0ef0772b078bd295301bd675afdee00d40e9.zip
Switched ito* to synchro*, except the server, I'm thinking of takeing the core
in a different direction anyway. Added the Deflate class, it uses zlib, and can do raw (headerless) deflate streams, zlib format, or gzip format. It's easy to use and quite versitile.
Diffstat (limited to 'src/synchroqueue.h')
-rw-r--r--src/synchroqueue.h240
1 files changed, 240 insertions, 0 deletions
diff --git a/src/synchroqueue.h b/src/synchroqueue.h
new file mode 100644
index 0000000..79d5e49
--- /dev/null
+++ b/src/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