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