Go to the documentation of this file.00001 #ifndef FCAM_TSQUEUE_H
00002 #define FCAM_TSQUEUE_H
00003
00004 #include <deque>
00005 #include <iterator>
00006 #include <semaphore.h>
00007 #include <pthread.h>
00008
00009 #include <errno.h>
00010 #include <string.h>
00011
00012
00013
00023 namespace FCam {
00024
00030 template<typename T>
00031 class TSQueue {
00032 public:
00033 TSQueue();
00034 ~TSQueue();
00035
00038 class locking_iterator;
00039
00041 void push(const T& val);
00043 void pop();
00044
00046 void pushFront(const T& val);
00048 void popBack();
00049
00052 T& front();
00053 const T& front() const;
00054
00057 T& back();
00058 const T& back() const;
00059
00061 bool empty() const;
00063 size_t size() const;
00064
00067 bool wait(unsigned int timeout=0);
00068
00076 T pull();
00077
00079 T pullBack();
00080
00083 bool tryPull(T *);
00084 bool tryPullBack(T *);
00085
00089 locking_iterator begin();
00093 locking_iterator end();
00101 bool erase(TSQueue<T>::locking_iterator);
00102
00103 private:
00104 std::deque<T> q;
00105 mutable pthread_mutex_t mutex;
00106 sem_t *sem;
00107
00108 friend class locking_iterator;
00109 };
00110
00111 template<typename T>
00112 class TSQueue<T>::locking_iterator: public std::iterator< std::random_access_iterator_tag, T> {
00113 public:
00114 locking_iterator();
00115 locking_iterator(TSQueue<T> *, typename std::deque<T>::iterator i);
00116 locking_iterator(const TSQueue<T>::locking_iterator &);
00117 ~locking_iterator();
00118 locking_iterator& operator=(const TSQueue<T>::locking_iterator &);
00119
00120 locking_iterator& operator++();
00121 locking_iterator operator++(int);
00122 locking_iterator& operator--();
00123 locking_iterator operator--(int);
00124
00125 locking_iterator operator+(int);
00126 locking_iterator operator-(int);
00127
00128 locking_iterator& operator+=(int);
00129 locking_iterator& operator-=(int);
00130
00131 int operator-(const TSQueue<T>::locking_iterator &);
00132
00133 bool operator==(const TSQueue<T>::locking_iterator &other);
00134 bool operator!=(const TSQueue<T>::locking_iterator &other);
00135 bool operator<(const TSQueue<T>::locking_iterator &other);
00136 bool operator>(const TSQueue<T>::locking_iterator &other);
00137 bool operator<=(const TSQueue<T>::locking_iterator &other);
00138 bool operator>=(const TSQueue<T>::locking_iterator &other);
00139
00140 T& operator*();
00141 T* operator->();
00142 private:
00143 TSQueue *parent;
00144 typename std::deque<T>::iterator qi;
00145
00146 friend class TSQueue<T>;
00147 };
00148
00149 template<typename T>
00150 TSQueue<T>::TSQueue() {
00151 pthread_mutexattr_t mutexAttr;
00152 pthread_mutexattr_init(&mutexAttr);
00153 pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE);
00154 pthread_mutex_init(&mutex, &mutexAttr);
00155 #ifdef FCAM_PLATFORM_OSX
00156
00157 char semName[256];
00158
00159 snprintf(semName, 256, "FCam::TSQueue::sem::%llx", (long long unsigned)this);
00160 sem = sem_open(semName, O_CREAT, 666, 0);
00161 #else
00162 sem = new sem_t;
00163 sem_init(sem, 0, 0);
00164 #endif
00165
00166 }
00167
00168 template<typename T>
00169 TSQueue<T>::~TSQueue() {
00170 pthread_mutex_destroy(&mutex);
00171 #ifdef FCAM_PLATFORM_OSX
00172 sem_close(sem);
00173 char semName[256];
00174
00175 snprintf(semName, 256, "FCam::TSQueue::sem::%llx", (long long unsigned)this);
00176 sem_unlink(semName);
00177 #else
00178 sem_destroy(sem);
00179 delete sem;
00180 #endif
00181 }
00182
00183 template<typename T>
00184 void TSQueue<T>::push(const T& val) {
00185
00186 pthread_mutex_lock(&mutex);
00187 q.push_back(val);
00188 pthread_mutex_unlock(&mutex);
00189 sem_post(sem);
00190 }
00191
00192 template<typename T>
00193 void TSQueue<T>::pushFront(const T& val) {
00194 pthread_mutex_lock(&mutex);
00195 q.push_front(val);
00196 pthread_mutex_unlock(&mutex);
00197 sem_post(sem);
00198 }
00199
00200 template<typename T>
00201 void TSQueue<T>::pop() {
00202
00203 sem_wait(sem);
00204 pthread_mutex_lock(&mutex);
00205 q.pop_front();
00206 pthread_mutex_unlock(&mutex);
00207 }
00208
00209 template<typename T>
00210 void TSQueue<T>::popBack() {
00211
00212 sem_wait(sem);
00213 pthread_mutex_lock(&mutex);
00214 q.pop_back();
00215 pthread_mutex_unlock(&mutex);
00216 }
00217
00218 template<typename T>
00219 T& TSQueue<T>::front() {
00220 pthread_mutex_lock(&mutex);
00221 T &val = q.front();
00222 pthread_mutex_unlock(&mutex);
00223 return val;
00224 }
00225
00226 template<typename T>
00227 const T& TSQueue<T>::front() const{
00228 const T &val;
00229 pthread_mutex_lock(&mutex);
00230 val = q.front();
00231 pthread_mutex_unlock(&mutex);
00232 return val;
00233 }
00234
00235 template<typename T>
00236 T& TSQueue<T>::back() {
00237 T &val;
00238 pthread_mutex_lock(&mutex);
00239 val = q.back();
00240 pthread_mutex_unlock(&mutex);
00241 return val;
00242 }
00243
00244 template<typename T>
00245 const T& TSQueue<T>::back() const {
00246 const T &val;
00247 pthread_mutex_lock(&mutex);
00248 val = q.back();
00249 pthread_mutex_unlock(&mutex);
00250 return val;
00251 }
00252
00253 template<typename T>
00254 bool TSQueue<T>::empty() const {
00255 bool _empty;
00256 pthread_mutex_lock(&mutex);
00257 _empty = q.empty();
00258 pthread_mutex_unlock(&mutex);
00259 return _empty;
00260 }
00261
00262 template<typename T>
00263 size_t TSQueue<T>::size() const {
00264 size_t _size;
00265 pthread_mutex_lock(&mutex);
00266 _size = q.size();
00267 pthread_mutex_unlock(&mutex);
00268 return _size;
00269 }
00270
00271 template<typename T>
00272 bool TSQueue<T>::wait(unsigned int timeout) {
00273 bool res;
00274 int err;
00275 if (timeout == 0) {
00276 err=sem_wait(sem);
00277 } else {
00278 #ifndef FCAM_PLATFORM_OSX // No clock_gettime or sem_timedwait on OSX
00279 timespec tv;
00280
00281 clock_gettime(CLOCK_REALTIME, &tv);
00282 tv.tv_nsec += timeout*1000;
00283 tv.tv_sec += tv.tv_nsec / 1000000000;
00284 tv.tv_nsec = tv.tv_nsec % 1000000000;
00285 err=sem_timedwait(sem, &tv);
00286 #else
00287 err=sem_trywait(sem);
00288 #endif
00289 }
00290 if (err == -1) {
00291 switch (errno) {
00292 case EINTR:
00293 case ETIMEDOUT:
00294 res = false;
00295 break;
00296 default:
00297
00298 res = false;
00299 break;
00300 }
00301 } else {
00302 res = true;
00303 sem_post(sem);
00304 }
00305
00306 return res;
00307 }
00308
00309 template<typename T>
00310 T TSQueue<T>::pull() {
00311
00312 sem_wait(sem);
00313 pthread_mutex_lock(&mutex);
00314 T copyVal = q.front();
00315 q.pop_front();
00316 pthread_mutex_unlock(&mutex);
00317
00318 return copyVal;
00319 }
00320
00321 template<typename T>
00322 T TSQueue<T>::pullBack() {
00323 sem_wait(sem);
00324 pthread_mutex_lock(&mutex);
00325 T copyVal = q.back();
00326 q.pop_back();
00327 pthread_mutex_unlock(&mutex);
00328 return copyVal;
00329 }
00330
00331 template<typename T>
00332 bool TSQueue<T>::tryPull(T *ptr) {
00333 if (sem_trywait(sem)) return false;
00334 pthread_mutex_lock(&mutex);
00335 T copyVal = q.front();
00336 q.pop_front();
00337 pthread_mutex_unlock(&mutex);
00338 *ptr = copyVal;
00339 return true;
00340 }
00341
00342 template<typename T>
00343 bool TSQueue<T>::tryPullBack(T *ptr) {
00344 if (sem_trywait(sem)) return false;
00345 pthread_mutex_lock(&mutex);
00346 T copyVal = q.back();
00347 q.pop_back();
00348 pthread_mutex_unlock(&mutex);
00349 *ptr = copyVal;
00350 return true;
00351 }
00352
00353 template<typename T>
00354 typename TSQueue<T>::locking_iterator TSQueue<T>::begin() {
00355 return locking_iterator(this, q.begin());
00356 }
00357
00358 template<typename T>
00359 typename TSQueue<T>::locking_iterator TSQueue<T>::end() {
00360 return locking_iterator(this, q.end());
00361 }
00362
00363 template<typename T>
00364 bool TSQueue<T>::erase(TSQueue<T>::locking_iterator li) {
00365
00366 if (sem_trywait(sem)) {
00367 return false;
00368 }
00369 q.erase(li.qi);
00370 return true;
00371 }
00372
00373 template<typename T>
00374 TSQueue<T>::locking_iterator::locking_iterator() : parent(NULL), qi()
00375 {}
00376
00377 template<typename T>
00378 TSQueue<T>::locking_iterator::locking_iterator(TSQueue<T> *p,
00379 typename std::deque<T>::iterator i) :
00380 parent(p), qi(i)
00381 {
00382 if (parent) {
00383 pthread_mutex_lock(&(parent->mutex));
00384 }
00385 }
00386
00387 template<typename T>
00388 TSQueue<T>::locking_iterator::locking_iterator(const TSQueue<T>::locking_iterator &other):
00389 parent(other.parent), qi(other.qi)
00390 {
00391 if (parent) {
00392 pthread_mutex_lock(&(parent->mutex));
00393 }
00394 }
00395
00396 template<typename T>
00397 TSQueue<T>::locking_iterator::~locking_iterator() {
00398 if (parent) {
00399 pthread_mutex_unlock(&(parent->mutex));
00400 }
00401 }
00402
00403 template<typename T>
00404 typename TSQueue<T>::locking_iterator &TSQueue<T>::locking_iterator::operator=(const TSQueue<T>::locking_iterator &other) {
00405 if (&other == this) return (*this);
00406 if (parent &&
00407 other.qi == qi) return (*this);
00408
00409 if (parent) pthread_mutex_unlock(&(parent->mutex));
00410 parent = other.parent;
00411 qi = other.qi;
00412 if (parent) pthread_mutex_lock(&(parent->mutex));
00413
00414 }
00415
00416 template<typename T>
00417 typename TSQueue<T>::locking_iterator &TSQueue<T>::locking_iterator::operator++() {
00418 qi++;
00419 return (*this);
00420 }
00421
00422 template<typename T>
00423 typename TSQueue<T>::locking_iterator TSQueue<T>::locking_iterator::operator++(int) {
00424 typename TSQueue<T>::locking_iterator temp(*this);
00425 qi++;
00426 return temp;
00427 }
00428
00429 template<typename T>
00430 typename TSQueue<T>::locking_iterator &TSQueue<T>::locking_iterator::operator--() {
00431 qi--;
00432 return (*this);
00433 }
00434
00435 template<typename T>
00436 typename TSQueue<T>::locking_iterator TSQueue<T>::locking_iterator::operator--(int) {
00437 typename TSQueue<T>::locking_iterator temp(*this);
00438 qi--;
00439 return temp;
00440 }
00441
00442 template<typename T>
00443 typename TSQueue<T>::locking_iterator TSQueue<T>::locking_iterator::operator+(int n) {
00444 typename TSQueue<T>::locking_iterator temp(*this);
00445 temp+=n;
00446 return temp;
00447 }
00448
00449 template<typename T>
00450 typename TSQueue<T>::locking_iterator operator+(int n,
00451 typename TSQueue<T>::locking_iterator l) {
00452 return l+n;
00453 }
00454
00455 template<typename T>
00456 typename TSQueue<T>::locking_iterator TSQueue<T>::locking_iterator::operator-(int n) {
00457 typename TSQueue<T>::locking_iterator temp(*this);
00458 temp-=n;
00459 return temp;
00460 }
00461
00462 template<typename T>
00463 typename TSQueue<T>::locking_iterator &TSQueue<T>::locking_iterator::operator+=(int n) {
00464 qi += n;
00465 return *this;
00466 }
00467
00468 template<typename T>
00469 typename TSQueue<T>::locking_iterator &TSQueue<T>::locking_iterator::operator-=(int n) {
00470 qi -= n;
00471 return *this;
00472 }
00473
00474 template<typename T>
00475 int TSQueue<T>::locking_iterator::operator-(const TSQueue<T>::locking_iterator &other) {
00476 return qi - other.qi;
00477 }
00478
00479 template<typename T>
00480 bool TSQueue<T>::locking_iterator::operator==(const TSQueue<T>::locking_iterator &other) {
00481 return qi == other.qi;
00482 }
00483
00484 template<typename T>
00485 bool TSQueue<T>::locking_iterator::operator!=(const TSQueue<T>::locking_iterator &other) {
00486 return qi != other.qi;
00487 }
00488
00489 template<typename T>
00490 bool TSQueue<T>::locking_iterator::operator<(const TSQueue<T>::locking_iterator &other) {
00491 return qi < other.qi;
00492 }
00493
00494 template<typename T>
00495 bool TSQueue<T>::locking_iterator::operator>(const TSQueue<T>::locking_iterator &other) {
00496 return qi > other.qi;
00497 }
00498
00499 template<typename T>
00500 bool TSQueue<T>::locking_iterator::operator<=(const TSQueue<T>::locking_iterator &other) {
00501 return qi <= other.qi;
00502 }
00503
00504 template<typename T>
00505 bool TSQueue<T>::locking_iterator::operator>=(const TSQueue<T>::locking_iterator &other) {
00506 return qi >= other.qi;
00507 }
00508
00509 template<typename T>
00510 T& TSQueue<T>::locking_iterator::operator*() {
00511 return *qi;
00512 }
00513
00514 template<typename T>
00515 T* TSQueue<T>::locking_iterator::operator->() {
00516 return &(*qi);
00517 }
00518
00519 }
00520
00521 #endif