• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

include/FCam/TSQueue.h

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 //#include "../../src/Debug.h"
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         // unnamed semaphores not supported on OSX
00159         char semName[256];
00160         // Create a unique semaphore name for this TSQueue using its pointer value
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         //dprintf(6,"TSQueue %llx initialized\n", (long long unsigned)this);
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         // Recreate the unique semaphore name for this TSQueue using its pointer value
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         //dprintf(6, "Pushing to queue %llx\n",(long long unsigned)this);
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         // Only safe for a single consumer!!!
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         // Only safe for a single consumer!!!
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             // This will overflow around 1 hour or so of timeout
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                 //error(Event::InternalError, "TSQueue::wait: Unexpected error from wait on semaphore: %s", strerror(errno));
00319                 res = false;
00320                 break;
00321             }
00322         } else {
00323             res = true;
00324             sem_post(sem); // Put back the semaphore since we're not actually popping
00325         }
00326 
00327         return res;
00328     }
00329 
00330     template<typename T>
00331     T TSQueue<T>::pull() {
00332         //dprintf(6, "Pulling from queue %llx\n",(long long unsigned)this);
00333         sem_wait(sem);
00334         pthread_mutex_lock(&mutex);
00335         T copyVal = q.front();
00336         q.pop_front();
00337         pthread_mutex_unlock(&mutex);
00338         //dprintf(6, "Done pull from queue %llx\n",(long long unsigned)this);
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         /* Since we're erasing, decrement semaphore. */
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

Generated on Mon Aug 16 2010 14:25:45 for FCam by  doxygen 1.7.1