diff options
Diffstat (limited to 'src/stable/synchroqueue.h')
-rw-r--r-- | src/stable/synchroqueue.h | 240 |
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 | |||
16 | namespace 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 | ||